summaryrefslogtreecommitdiffstats
path: root/sd/source/ui/slideshow
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sd/source/ui/slideshow
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/slideshow')
-rw-r--r--sd/source/ui/slideshow/PaneHider.cxx99
-rw-r--r--sd/source/ui/slideshow/PaneHider.hxx66
-rw-r--r--sd/source/ui/slideshow/SlideShowRestarter.cxx157
-rw-r--r--sd/source/ui/slideshow/SlideShowRestarter.hxx87
-rw-r--r--sd/source/ui/slideshow/showwin.cxx633
-rw-r--r--sd/source/ui/slideshow/showwindow.hxx110
-rw-r--r--sd/source/ui/slideshow/slideshow.cxx1189
-rw-r--r--sd/source/ui/slideshow/slideshowimpl.cxx3619
-rw-r--r--sd/source/ui/slideshow/slideshowimpl.hxx355
-rw-r--r--sd/source/ui/slideshow/slideshowviewimpl.cxx626
-rw-r--r--sd/source/ui/slideshow/slideshowviewimpl.hxx182
11 files changed, 7123 insertions, 0 deletions
diff --git a/sd/source/ui/slideshow/PaneHider.cxx b/sd/source/ui/slideshow/PaneHider.cxx
new file mode 100644
index 0000000000..6207bf156a
--- /dev/null
+++ b/sd/source/ui/slideshow/PaneHider.cxx
@@ -0,0 +1,99 @@
+/* -*- 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 "PaneHider.hxx"
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include "slideshowimpl.hxx"
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::lang::DisposedException;
+
+namespace sd
+{
+PaneHider::PaneHider(const ViewShell& rViewShell, SlideshowImpl* pSlideShow)
+{
+ // Hide the left and right pane windows when a slideshow exists and is
+ // not full screen.
+ if (pSlideShow == nullptr || pSlideShow->isFullScreen())
+ return;
+
+ try
+ {
+ Reference<XControllerManager> xControllerManager(
+ rViewShell.GetViewShellBase().GetController(), UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ // Get and save the current configuration.
+ mxConfiguration = mxConfigurationController->getRequestedConfiguration();
+ if (mxConfiguration.is())
+ {
+ // Iterate over the resources and deactivate the panes.
+ const Sequence<Reference<XResourceId>> aResources(mxConfiguration->getResources(
+ nullptr, framework::FrameworkHelper::msPaneURLPrefix,
+ AnchorBindingMode_DIRECT));
+ for (const Reference<XResourceId>& xPaneId : aResources)
+ {
+ if (xPaneId->getResourceURL() != FrameworkHelper::msCenterPaneURL)
+ {
+ mxConfigurationController->requestResourceDeactivation(xPaneId);
+ }
+ }
+ }
+ }
+ FrameworkHelper::Instance(rViewShell.GetViewShellBase())->WaitForUpdate();
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+PaneHider::~PaneHider()
+{
+ if (mxConfiguration.is() && mxConfigurationController.is())
+ {
+ try
+ {
+ mxConfigurationController->restoreConfiguration(mxConfiguration);
+ }
+ catch (DisposedException&)
+ {
+ // When the configuration controller is already disposed then
+ // there is no point in restoring the configuration.
+ }
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/PaneHider.hxx b/sd/source/ui/slideshow/PaneHider.hxx
new file mode 100644
index 0000000000..a2d3cabb01
--- /dev/null
+++ b/sd/source/ui/slideshow/PaneHider.hxx
@@ -0,0 +1,66 @@
+/* -*- 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 <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+
+namespace sd
+{
+class ViewShell;
+class SlideshowImpl;
+
+/** Hide the windows of the side panes and restore the original visibility
+ later. Used by the in-window slide show in order to use the whole frame
+ window for the show.
+*/
+class PaneHider
+{
+public:
+ /** The constructor hides all side panes that belong to the
+ ViewShellBase of the given view shell.
+ */
+ PaneHider(const ViewShell& rViewShell, SlideshowImpl* pSlideShow);
+
+ /** Restore the original visibility of the side panes.
+ */
+ ~PaneHider();
+
+private:
+ /** Remember whether the visibility states of the windows of the panes
+ has been modified and have to be restored.
+ */
+
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/SlideShowRestarter.cxx b/sd/source/ui/slideshow/SlideShowRestarter.cxx
new file mode 100644
index 0000000000..a9b53acf11
--- /dev/null
+++ b/sd/source/ui/slideshow/SlideShowRestarter.cxx
@@ -0,0 +1,157 @@
+/* -*- 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 <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <slideshow.hxx>
+#include "SlideShowRestarter.hxx"
+
+#include <comphelper/propertyvalue.hxx>
+#include <framework/ConfigurationController.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <functional>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd {
+
+SlideShowRestarter::SlideShowRestarter (
+ ::rtl::Reference<SlideShow> pSlideShow,
+ ViewShellBase* pViewShellBase)
+ : mnEventId(nullptr),
+ mpSlideShow(std::move(pSlideShow)),
+ mpViewShellBase(pViewShellBase),
+ mnDisplayCount(Application::GetScreenCount()),
+ mpDispatcher(pViewShellBase->GetViewFrame().GetDispatcher()),
+ mnCurrentSlideNumber(0)
+{
+}
+
+SlideShowRestarter::~SlideShowRestarter()
+{
+}
+
+void SlideShowRestarter::Restart (bool bForce)
+{
+ // Prevent multiple and concurrently restarts.
+ if (mnEventId != nullptr)
+ return;
+
+ if (bForce)
+ mnDisplayCount = 0;
+
+ // Remember the current slide in order to restore it after the slide
+ // show has been restarted.
+ if (mpSlideShow.is())
+ mnCurrentSlideNumber = mpSlideShow->getCurrentPageNumber();
+
+ // Remember a shared pointer to this object to prevent its destruction
+ // before the whole restarting process has finished.
+ mpSelf = shared_from_this();
+
+ // We do not know in what situation this method was called. So, in
+ // order to be able to cleanly stop the presentation, we do that
+ // asynchronously.
+ mnEventId = Application::PostUserEvent(
+ LINK(this, SlideShowRestarter, EndPresentation));
+}
+
+IMPL_LINK_NOARG(SlideShowRestarter, EndPresentation, void*, void)
+{
+ mnEventId = nullptr;
+ if (!mpSlideShow.is())
+ return;
+
+ if (mnDisplayCount == static_cast<sal_Int32>(Application::GetScreenCount()))
+ return;
+
+ bool bIsExitAfterPresenting = mpSlideShow->IsExitAfterPresenting();
+ mpSlideShow->SetExitAfterPresenting(false);
+ mpSlideShow->end();
+ mpSlideShow->SetExitAfterPresenting(bIsExitAfterPresenting);
+
+ // The following piece of code should not be here because the
+ // slide show should be aware of the existence of the presenter
+ // console (which is displayed in the FullScreenPane). But the
+ // timing has to be right and I did not find a better place for
+ // it.
+
+ // Wait for the full screen pane, which displays the presenter
+ // console, to disappear. Only when it is gone, call
+ // InitiatePresenterStart(), in order to begin the asynchronous
+ // restart of the slide show.
+ if (mpViewShellBase == nullptr)
+ return;
+
+ ::std::shared_ptr<FrameworkHelper> pHelper(
+ FrameworkHelper::Instance(*mpViewShellBase));
+ if (pHelper->GetConfigurationController()->getResource(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msFullScreenPaneURL)).is())
+ {
+ ::sd::framework::ConfigurationController::Lock aLock (
+ pHelper->GetConfigurationController());
+
+ pHelper->RunOnConfigurationEvent(
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ ::std::bind(&SlideShowRestarter::StartPresentation, shared_from_this()));
+ pHelper->UpdateConfiguration();
+ }
+ else
+ {
+ StartPresentation();
+ }
+}
+
+void SlideShowRestarter::StartPresentation()
+{
+ //rhbz#1091117 crash because we're exiting the application, and this is
+ //being called during the configuration update event on exit. At this point
+ //newly created objects won't get disposed called on them, because the
+ //disposer is doing its last execution of that now.
+ if (mpViewShellBase && mpViewShellBase->GetDrawController()->IsDisposing())
+ return;
+
+ if (mpDispatcher == nullptr && mpViewShellBase!=nullptr)
+ mpDispatcher = mpViewShellBase->GetViewFrame().GetDispatcher();
+
+ // Start the slide show on the saved current slide.
+ if (mpDispatcher != nullptr)
+ {
+ mpDispatcher->Execute(SID_PRESENTATION, SfxCallMode::ASYNCHRON);
+ if (mpSlideShow.is())
+ {
+ Sequence aProperties{ comphelper::makePropertyValue("FirstPage",
+ "page" + OUString::number(mnCurrentSlideNumber+1)) };
+ mpSlideShow->startWithArguments(aProperties);
+ }
+ mpSelf.reset();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/SlideShowRestarter.hxx b/sd/source/ui/slideshow/SlideShowRestarter.hxx
new file mode 100644
index 0000000000..f8cf95c33a
--- /dev/null
+++ b/sd/source/ui/slideshow/SlideShowRestarter.hxx
@@ -0,0 +1,87 @@
+/* -*- 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 <rtl/ref.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+namespace sd
+{
+class SlideShow;
+}
+namespace sd
+{
+class ViewShellBase;
+}
+class SfxDispatcher;
+struct ImplSVEvent;
+
+namespace sd
+{
+/** This class is used when a display is removed or added to restart the
+ slide show. This is necessary at least with DirectX because
+ deactivating a display invalidates DirectX resources. Accessing those
+ leads to a crash.
+
+ During a restart a possibly installed presenter extension is given the
+ opportunity to show or hide depending on the number of available displays.
+*/
+class SlideShowRestarter : public std::enable_shared_from_this<SlideShowRestarter>
+{
+public:
+ /** Create a new SlideShowRestarter object.
+ @param rpSlideShow
+ The slide show is used to determine the current slide, which is
+ restored after the restart, and of course to stop and start the
+ slide show.
+ @param pViewShellBase
+ Used to get access to a slot dispatcher.
+ */
+ SlideShowRestarter(::rtl::Reference<SlideShow> pSlideShow, ViewShellBase* pViewShellBase);
+ virtual ~SlideShowRestarter();
+
+ /** Restarting the slide show is an asynchronous multi step process
+ which is started by calling this method.
+ @param bForce
+ Used to force a re-start, even if the display count is unchanged.
+ */
+ void Restart(bool bForce);
+
+private:
+ ImplSVEvent* mnEventId;
+ ::rtl::Reference<SlideShow> mpSlideShow;
+ ViewShellBase* mpViewShellBase;
+ ::std::shared_ptr<SlideShowRestarter> mpSelf;
+ sal_Int32 mnDisplayCount;
+ SfxDispatcher* mpDispatcher;
+ sal_Int32 mnCurrentSlideNumber;
+
+ DECL_LINK(EndPresentation, void*, void);
+
+ /** Restart the presentation on the slide last shown before the restart
+ was initiated.
+ */
+ void StartPresentation();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/showwin.cxx b/sd/source/ui/slideshow/showwin.cxx
new file mode 100644
index 0000000000..d6ecc19a69
--- /dev/null
+++ b/sd/source/ui/slideshow/showwin.cxx
@@ -0,0 +1,633 @@
+/* -*- 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 <com/sun/star/awt/Key.hpp>
+
+#include "showwindow.hxx"
+#include "slideshowimpl.hxx"
+
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxsids.hrc>
+
+
+#include <slideshow.hxx>
+#include <ViewShell.hxx>
+#include <sdresid.hxx>
+#include <helpids.h>
+#include <strings.hrc>
+
+#include <sal/log.hxx>
+#include <utility>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <tools/duration.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+const sal_uInt64 HIDE_MOUSE_TIMEOUT = 10000;
+const sal_uInt64 SHOW_MOUSE_TIMEOUT = 1000;
+
+ShowWindow::ShowWindow( ::rtl::Reference< SlideshowImpl > xController, vcl::Window* pParent )
+: ::sd::Window( pParent )
+, maPauseTimer("sd ShowWindow maPauseTimer")
+, maMouseTimer("sd ShowWindow maMouseTimer")
+, mnPauseTimeout( SLIDE_NO_TIMEOUT )
+, mnRestartPageIndex( PAGE_NO_END )
+, meShowWindowMode(SHOWWINDOWMODE_NORMAL)
+, mbShowNavigatorAfterSpecialMode( false )
+, mbMouseAutoHide(true)
+, mbMouseCursorHidden(false)
+, mnFirstMouseMove(0)
+, mxController(std::move( xController ))
+{
+ GetOutDev()->SetOutDevViewType( OutDevViewType::SlideShow );
+
+ // Do never mirror the preview window. This explicitly includes right
+ // to left writing environments.
+ EnableRTL (false);
+
+ MapMode aMap(GetMapMode());
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ SetMapMode(aMap);
+
+ // set HelpId
+ SetHelpId( HID_SD_WIN_PRESENTATION );
+
+ maPauseTimer.SetInvokeHandler( LINK( this, ShowWindow, PauseTimeoutHdl ) );
+ maPauseTimer.SetTimeout( 1000 );
+ maMouseTimer.SetInvokeHandler( LINK( this, ShowWindow, MouseTimeoutHdl ) );
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+
+ maShowBackground = Wallpaper( COL_BLACK );
+ SetBackground(); // avoids that VCL paints any background!
+ GetParent()->Show();
+ AddEventListener( LINK( this, ShowWindow, EventHdl ) );
+}
+
+ShowWindow::~ShowWindow()
+{
+ disposeOnce();
+}
+
+void ShowWindow::dispose()
+{
+ maPauseTimer.Stop();
+ maMouseTimer.Stop();
+ ::sd::Window::dispose();
+}
+
+void ShowWindow::KeyInput(const KeyEvent& rKEvt)
+{
+ // Ignore workaround of https://gitlab.gnome.org/GNOME/gtk/issues/1785
+ // See calls to GtkSalFrame::makeFakeKeyPress (Fixed in GTK 3.24)
+ bool bFakeKeyPress = rKEvt.GetKeyCode().GetFullCode() == 0;
+ if (bFakeKeyPress)
+ return;
+
+ bool bReturn = false;
+
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ bReturn = true;
+ }
+ else if( SHOWWINDOWMODE_END == meShowWindowMode )
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_PAGEUP:
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_P:
+ case KEY_HOME:
+ case KEY_END:
+ case awt::Key::CONTEXTMENU:
+ // these keys will be handled by the slide show even
+ // while in end mode
+ break;
+ default:
+ TerminateShow();
+ bReturn = true;
+ }
+ }
+ else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
+ {
+ RestartShow();
+ bReturn = true;
+ }
+ else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_ESCAPE:
+ TerminateShow();
+ bReturn = true;
+ break;
+ case KEY_PAGEUP:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_P:
+ case KEY_HOME:
+ case KEY_END:
+ case awt::Key::CONTEXTMENU:
+ // these keys will be handled by the slide show even
+ // while in end mode
+ break;
+ default:
+ RestartShow();
+ bReturn = true;
+ break;
+ }
+ }
+
+ if( !bReturn )
+ {
+ if( mxController.is() )
+ bReturn = mxController->keyInput(rKEvt);
+
+ if( !bReturn )
+ {
+ if( mpViewShell )
+ {
+ mpViewShell->KeyInput(rKEvt,this);
+ }
+ else
+ {
+ Window::KeyInput(rKEvt);
+ }
+ }
+ }
+
+ if( mpViewShell )
+ mpViewShell->SetActiveWindow( this );
+}
+
+void ShowWindow::MouseButtonDown(const MouseEvent& /*rMEvt*/)
+{
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ }
+ else if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow( this );
+ }
+}
+
+void ShowWindow::MouseMove(const MouseEvent& /*rMEvt*/)
+{
+ if( mbMouseAutoHide )
+ {
+ if( mbMouseCursorHidden )
+ {
+ if( mnFirstMouseMove )
+ {
+ // if this is not the first mouse move while hidden, see if
+ // enough time has pasted to show mouse pointer again
+ sal_uInt64 nTime = ::tools::Time::GetSystemTicks();
+ if( (nTime - mnFirstMouseMove) >= SHOW_MOUSE_TIMEOUT )
+ {
+ ShowPointer( true );
+ mnFirstMouseMove = 0;
+ mbMouseCursorHidden = false;
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+ else
+ {
+ // if this is the first mouse move, note current
+ // time and start idle timer to cancel show mouse pointer
+ // again if not enough mouse movement is measured
+ mnFirstMouseMove = ::tools::Time::GetSystemTicks();
+ maMouseTimer.SetTimeout( 2*SHOW_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+ else
+ {
+ // current mousemove restarts the idle timer to hide the mouse
+ maMouseTimer.Start();
+ }
+ }
+
+ if( mpViewShell )
+ mpViewShell->SetActiveWindow( this );
+}
+
+void ShowWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ }
+ else if( (SHOWWINDOWMODE_END == meShowWindowMode) && !rMEvt.IsRight() )
+ {
+ TerminateShow();
+ }
+ else if( (( SHOWWINDOWMODE_BLANK == meShowWindowMode ) || ( SHOWWINDOWMODE_PAUSE == meShowWindowMode ))
+ && !rMEvt.IsRight() )
+ {
+ RestartShow();
+ }
+ else
+ {
+ if( mxController.is() )
+ mxController->mouseButtonUp( rMEvt );
+ }
+}
+
+/**
+ * if FuSlideShow is still available, forward it
+ */
+void ShowWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect)
+{
+ if( (meShowWindowMode == SHOWWINDOWMODE_NORMAL) || (meShowWindowMode == SHOWWINDOWMODE_PREVIEW) )
+ {
+ if( mxController.is() )
+ {
+ mxController->paint();
+ }
+ else if(mpViewShell )
+ {
+ mpViewShell->Paint(rRect, this);
+ }
+ }
+ else
+ {
+ GetOutDev()->DrawWallpaper( rRect, maShowBackground );
+
+ if( SHOWWINDOWMODE_END == meShowWindowMode )
+ {
+ DrawEndScene();
+ }
+ else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
+ {
+ DrawPauseScene( false );
+ }
+ else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
+ {
+ // just blank through background color => nothing to be done here
+ }
+ }
+}
+
+void ShowWindow::LoseFocus()
+{
+ Window::LoseFocus();
+
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode)
+ TerminateShow();
+}
+
+void ShowWindow::SetEndMode()
+{
+ if( !(( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView()) )
+ return;
+
+ DeleteWindowFromPaintView();
+ meShowWindowMode = SHOWWINDOWMODE_END;
+ maShowBackground = Wallpaper( COL_BLACK );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ Invalidate();
+}
+
+bool ShowWindow::SetPauseMode( sal_Int32 nTimeout, Graphic const * pLogo )
+{
+ rtl::Reference< SlideShow > xSlideShow;
+
+ if( mpViewShell )
+ xSlideShow = SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() );
+
+ if( xSlideShow.is() && !nTimeout )
+ {
+ xSlideShow->jumpToPageIndex( 0 );
+ }
+ else if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
+ {
+ DeleteWindowFromPaintView();
+ mnPauseTimeout = nTimeout;
+ mnRestartPageIndex = 0;
+ meShowWindowMode = SHOWWINDOWMODE_PAUSE;
+ maShowBackground = Wallpaper( COL_BLACK );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ if( pLogo )
+ maLogo = *pLogo;
+
+ Invalidate();
+
+ if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
+ maPauseTimer.Start();
+ }
+
+ return( SHOWWINDOWMODE_PAUSE == meShowWindowMode );
+}
+
+bool ShowWindow::SetBlankMode( sal_Int32 nPageIndexToRestart, const Color& rBlankColor )
+{
+ if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
+ {
+ DeleteWindowFromPaintView();
+ mnRestartPageIndex = nPageIndexToRestart;
+ meShowWindowMode = SHOWWINDOWMODE_BLANK;
+ maShowBackground = Wallpaper( rBlankColor );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ Invalidate();
+ }
+
+ return( SHOWWINDOWMODE_BLANK == meShowWindowMode );
+}
+
+void ShowWindow::SetPreviewMode()
+{
+ meShowWindowMode = SHOWWINDOWMODE_PREVIEW;
+}
+
+void ShowWindow::TerminateShow()
+{
+ maLogo.Clear();
+ maPauseTimer.Stop();
+ maMouseTimer.Stop();
+ GetOutDev()->Erase();
+ maShowBackground = Wallpaper( COL_BLACK );
+ meShowWindowMode = SHOWWINDOWMODE_NORMAL;
+ mnPauseTimeout = SLIDE_NO_TIMEOUT;
+
+ if( mpViewShell )
+ {
+ // show navigator?
+ if( mbShowNavigatorAfterSpecialMode )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
+ mbShowNavigatorAfterSpecialMode = false;
+ }
+ }
+
+ if( mxController.is() )
+ mxController->endPresentation();
+
+ mnRestartPageIndex = PAGE_NO_END;
+}
+
+void ShowWindow::RestartShow()
+{
+ RestartShow( mnRestartPageIndex );
+}
+
+void ShowWindow::RestartShow( sal_Int32 nPageIndexToRestart )
+{
+ ShowWindowMode eOldShowWindowMode = meShowWindowMode;
+
+ maLogo.Clear();
+ maPauseTimer.Stop();
+ GetOutDev()->Erase();
+ maShowBackground = Wallpaper( COL_BLACK );
+ meShowWindowMode = SHOWWINDOWMODE_NORMAL;
+ mnPauseTimeout = SLIDE_NO_TIMEOUT;
+
+ if( mpViewShell )
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() ) );
+
+ if( xSlideShow.is() )
+ {
+ AddWindowToPaintView();
+
+ if( SHOWWINDOWMODE_BLANK == eOldShowWindowMode || SHOWWINDOWMODE_END == eOldShowWindowMode )
+ {
+ xSlideShow->pause(false);
+ Invalidate();
+ }
+ else
+ {
+ xSlideShow->jumpToPageIndex( nPageIndexToRestart );
+ }
+ }
+ }
+
+ mnRestartPageIndex = PAGE_NO_END;
+
+ // show navigator?
+ if( mbShowNavigatorAfterSpecialMode )
+ {
+ if (mpViewShell)
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
+ mbShowNavigatorAfterSpecialMode = false;
+ }
+}
+
+void ShowWindow::DrawPauseScene( bool bTimeoutOnly )
+{
+ const MapMode& rMap = GetMapMode();
+ const Point aOutOrg( PixelToLogic( Point() ) );
+ const Size aOutSize( GetOutDev()->GetOutputSize() );
+ const Size aTextSize(OutputDevice::LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), rMap));
+ const Size aOffset(OutputDevice::LogicToLogic(Size(1000, 1000), MapMode(MapUnit::Map100thMM), rMap));
+ OUString aText( SdResId( STR_PRES_PAUSE ) );
+ bool bDrawn = false;
+
+ vcl::Font aFont( GetSettings().GetStyleSettings().GetMenuFont() );
+ const vcl::Font aOldFont( GetFont() );
+
+ aFont.SetFontSize( aTextSize );
+ aFont.SetColor( COL_WHITE );
+ aFont.SetCharSet( aOldFont.GetCharSet() );
+ aFont.SetLanguage( aOldFont.GetLanguage() );
+
+ if( !bTimeoutOnly && ( maLogo.GetType() != GraphicType::NONE ) )
+ {
+ Size aGrfSize;
+
+ if (maLogo.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aGrfSize = PixelToLogic( maLogo.GetPrefSize() );
+ else
+ aGrfSize = OutputDevice::LogicToLogic( maLogo.GetPrefSize(), maLogo.GetPrefMapMode(), rMap );
+
+ const Point aGrfPos( std::max( aOutOrg.X() + aOutSize.Width() - aGrfSize.Width() - aOffset.Width(), aOutOrg.X() ),
+ std::max( aOutOrg.Y() + aOutSize.Height() - aGrfSize.Height() - aOffset.Height(), aOutOrg.Y() ) );
+
+ if( maLogo.IsAnimated() )
+ maLogo.StartAnimation(*GetOutDev(), aGrfPos, aGrfSize, reinterpret_cast<sal_IntPtr>(this));
+ else
+ maLogo.Draw(*GetOutDev(), aGrfPos, aGrfSize);
+ }
+
+ if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
+ {
+ MapMode aVMap( rMap );
+ ScopedVclPtrInstance< VirtualDevice > pVDev( *GetOutDev() );
+
+ aVMap.SetOrigin( Point() );
+ pVDev->SetMapMode( aVMap );
+ pVDev->SetBackground( Wallpaper( COL_BLACK ) );
+
+ // set font first, to determine real output height
+ pVDev->SetFont( aFont );
+
+ const Size aVDevSize( aOutSize.Width(), pVDev->GetTextHeight() );
+
+ if( pVDev->SetOutputSize( aVDevSize ) )
+ {
+ // Note: if performance gets an issue here, we can use NumberFormatter directly
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& aLocaleData = aSysLocale.GetLocaleData();
+
+ aText += " ( " + aLocaleData.getDuration( ::tools::Duration( 0, 0, 0, mnPauseTimeout, 0 )) + " )";
+ pVDev->DrawText( Point( aOffset.Width(), 0 ), aText );
+ GetOutDev()->DrawOutDev( Point( aOutOrg.X(), aOffset.Height() ), aVDevSize, Point(), aVDevSize, *pVDev );
+ bDrawn = true;
+ }
+ }
+
+ if( !bDrawn )
+ {
+ SetFont( aFont );
+ GetOutDev()->DrawText( Point( aOutOrg.X() + aOffset.Width(), aOutOrg.Y() + aOffset.Height() ), aText );
+ SetFont( aOldFont );
+ }
+}
+
+void ShowWindow::DrawEndScene()
+{
+ const vcl::Font aOldFont( GetFont() );
+ vcl::Font aFont( GetSettings().GetStyleSettings().GetMenuFont() );
+
+ const Point aOutOrg( PixelToLogic( Point() ) );
+ const Size aTextSize(OutputDevice::LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), GetMapMode()));
+ const OUString aText( SdResId( STR_PRES_SOFTEND ) );
+
+ aFont.SetFontSize( aTextSize );
+ aFont.SetColor( COL_WHITE );
+ aFont.SetCharSet( aOldFont.GetCharSet() );
+ aFont.SetLanguage( aOldFont.GetLanguage() );
+ SetFont( aFont );
+ GetOutDev()->DrawText( Point( aOutOrg.X() + aTextSize.Height(), aOutOrg.Y() + aTextSize.Height() ), aText );
+ SetFont( aOldFont );
+}
+
+IMPL_LINK( ShowWindow, PauseTimeoutHdl, Timer*, pTimer, void )
+{
+ if( !( --mnPauseTimeout ) )
+ RestartShow();
+ else
+ {
+ DrawPauseScene( true );
+ pTimer->Start();
+ }
+}
+
+IMPL_LINK_NOARG(ShowWindow, MouseTimeoutHdl, Timer *, void)
+{
+ if( mbMouseCursorHidden )
+ {
+ // not enough mouse movements since first recording so
+ // cancel show mouse pointer for now
+ mnFirstMouseMove = 0;
+ }
+ else
+ {
+ // mouse has been idle too long, hide pointer
+ ShowPointer( false );
+ mbMouseCursorHidden = true;
+ }
+}
+
+IMPL_LINK( ShowWindow, EventHdl, VclWindowEvent&, rEvent, void )
+{
+ if( mbMouseAutoHide )
+ {
+ if (rEvent.GetId() == VclEventId::WindowShow)
+ {
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+}
+
+void ShowWindow::DeleteWindowFromPaintView()
+{
+ if( mpViewShell->GetView() )
+ mpViewShell->GetView()->DeleteDeviceFromPaintView( *GetOutDev() );
+
+ sal_uInt16 nChild = GetChildCount();
+ while( nChild-- )
+ GetChild( nChild )->Show( false );
+}
+
+void ShowWindow::AddWindowToPaintView()
+{
+ if( mpViewShell->GetView() )
+ mpViewShell->GetView()->AddDeviceToPaintView( *GetOutDev(), nullptr );
+
+ sal_uInt16 nChild = GetChildCount();
+ while( nChild-- )
+ GetChild( nChild )->Show();
+}
+
+// Override the sd::Window's CreateAccessible to create a different accessible object
+css::uno::Reference<css::accessibility::XAccessible>
+ ShowWindow::CreateAccessible()
+{
+ css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible(false);
+ if (xAcc)
+ {
+ return xAcc;
+ }
+ if (mpViewShell != nullptr)
+ {
+ xAcc = mpViewShell->CreateAccessibleDocumentView (this);
+ SetAccessible(xAcc);
+ return xAcc;
+ }
+ else
+ {
+ SAL_WARN("sd", "::sd::Window::CreateAccessible: no view shell");
+ return vcl::Window::CreateAccessible ();
+ }
+}
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/showwindow.hxx b/sd/source/ui/slideshow/showwindow.hxx
new file mode 100644
index 0000000000..c7a1d9bf02
--- /dev/null
+++ b/sd/source/ui/slideshow/showwindow.hxx
@@ -0,0 +1,110 @@
+/* -*- 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 <rtl/ref.hxx>
+#include <sal/types.h>
+#include <vcl/timer.hxx>
+#include <vcl/graph.hxx>
+
+#include <Window.hxx>
+
+namespace sd {
+
+class SlideshowImpl;
+
+#define SLIDE_NO_TIMEOUT SAL_MAX_INT32
+
+enum ShowWindowMode
+{
+ SHOWWINDOWMODE_NORMAL = 0,
+ SHOWWINDOWMODE_PAUSE = 1,
+ SHOWWINDOWMODE_END = 2,
+ SHOWWINDOWMODE_BLANK = 3,
+ SHOWWINDOWMODE_PREVIEW = 4
+};
+
+class ShowWindow
+ : public ::sd::Window
+{
+
+public:
+ ShowWindow ( ::rtl::Reference< ::sd::SlideshowImpl > xController, vcl::Window* pParent );
+ virtual ~ShowWindow() override;
+ virtual void dispose() override;
+
+ void SetEndMode();
+ bool SetPauseMode( sal_Int32 nTimeoutSec, Graphic const * pLogo = nullptr );
+ bool SetBlankMode( sal_Int32 nPageIndexToRestart, const Color& rBlankColor );
+
+ const Color& GetBlankColor() const { return maShowBackground.GetColor(); }
+
+ void SetPreviewMode();
+
+ void SetMouseAutoHide( bool bMouseAutoHide ) { mbMouseAutoHide = bMouseAutoHide; }
+
+ ShowWindowMode GetShowWindowMode() const { return meShowWindowMode; }
+
+ void RestartShow( sal_Int32 nPageIndexToRestart );
+
+ virtual void LoseFocus() override;
+
+ virtual void KeyInput(const KeyEvent& rKEvt) override;
+ virtual void MouseMove(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect) override;
+ /// Override the sd::Window's CreateAccessible to create a different accessible object
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessible() override;
+
+ void TerminateShow();
+ void RestartShow();
+
+private:
+ void DrawPauseScene( bool bTimeoutOnly );
+ void DrawEndScene();
+
+ void DeleteWindowFromPaintView();
+ void AddWindowToPaintView();
+
+private:
+ Timer maPauseTimer;
+ Timer maMouseTimer;
+ Wallpaper maShowBackground;
+ Graphic maLogo;
+ sal_uLong mnPauseTimeout;
+ sal_Int32 mnRestartPageIndex;
+ ShowWindowMode meShowWindowMode;
+ bool mbShowNavigatorAfterSpecialMode;
+ bool mbMouseAutoHide;
+ bool mbMouseCursorHidden;
+ sal_uInt64 mnFirstMouseMove;
+
+ DECL_LINK( PauseTimeoutHdl, Timer*, void );
+ DECL_LINK(MouseTimeoutHdl, Timer *, void);
+ DECL_LINK( EventHdl, VclWindowEvent&, void );
+
+ ::rtl::Reference< SlideshowImpl > mxController;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshow.cxx b/sd/source/ui/slideshow/slideshow.cxx
new file mode 100644
index 0000000000..1c21ef7ee0
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshow.cxx
@@ -0,0 +1,1189 @@
+/* -*- 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 <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/util/URL.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdlayer.hxx>
+#include <svl/itemprop.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include <framework/FrameworkHelper.hxx>
+#include <comphelper/extract.hxx>
+
+#include <FrameView.hxx>
+#include <createpresentation.hxx>
+#include <unomodel.hxx>
+#include <slideshow.hxx>
+#include "slideshowimpl.hxx"
+#include <sdattr.hrc>
+#include <sdmod.hxx>
+#include <FactoryIds.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include "SlideShowRestarter.hxx"
+#include <DrawController.hxx>
+#include <PresentationViewShell.hxx>
+#include <customshowlist.hxx>
+#include <unopage.hxx>
+#include <sdpage.hxx>
+#include <cusshow.hxx>
+#include <optsitem.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+using ::com::sun::star::presentation::XSlideShowController;
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::awt::XWindow;
+using namespace ::sd;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+ /** This local version of the work window overrides DataChanged() so that it
+ can restart the slide show when a display is added or removed.
+ */
+ class FullScreenWorkWindow : public WorkWindow
+ {
+ public:
+ FullScreenWorkWindow (
+ const ::rtl::Reference<SlideShow>& rpSlideShow,
+ ViewShellBase* pViewShellBase)
+ : WorkWindow(nullptr, WB_HIDE | WB_CLIPCHILDREN),
+ mpRestarter(std::make_shared<SlideShowRestarter>(rpSlideShow, pViewShellBase))
+ {}
+
+ void Restart(bool bForce)
+ {
+ mpRestarter->Restart(bForce);
+ }
+
+ virtual void DataChanged (const DataChangedEvent& rEvent) override
+ {
+ if (rEvent.GetType() == DataChangedEventType::DISPLAY)
+ Restart(false);
+ }
+
+ private:
+ ::std::shared_ptr<SlideShowRestarter> mpRestarter;
+ };
+}
+
+static std::span<const SfxItemPropertyMapEntry> ImplGetPresentationPropertyMap()
+{
+ // NOTE: First member must be sorted
+ static const SfxItemPropertyMapEntry aPresentationPropertyMap_Impl[] =
+ {
+ { u"AllowAnimations"_ustr, ATTR_PRESENT_ANIMATION_ALLOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"CustomShow"_ustr, ATTR_PRESENT_CUSTOMSHOW, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"Display"_ustr, ATTR_PRESENT_DISPLAY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"FirstPage"_ustr, ATTR_PRESENT_DIANAME, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"IsAlwaysOnTop"_ustr, ATTR_PRESENT_ALWAYS_ON_TOP, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsAutomatic"_ustr, ATTR_PRESENT_MANUEL, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsEndless"_ustr, ATTR_PRESENT_ENDLESS, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsFullScreen"_ustr, ATTR_PRESENT_FULLSCREEN, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsShowAll"_ustr, ATTR_PRESENT_ALL, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsMouseVisible"_ustr, ATTR_PRESENT_MOUSE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsShowLogo"_ustr, ATTR_PRESENT_SHOW_PAUSELOGO, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsTransitionOnClick"_ustr, ATTR_PRESENT_CHANGE_PAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"Pause"_ustr, ATTR_PRESENT_PAUSE_TIMEOUT, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"StartWithNavigator"_ustr, ATTR_PRESENT_NAVIGATOR, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"UsePen"_ustr, ATTR_PRESENT_PEN, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+
+ return aPresentationPropertyMap_Impl;
+}
+
+
+SlideShow::SlideShow( SdDrawDocument* pDoc )
+: maPropSet(ImplGetPresentationPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool())
+, mbIsInStartup(false)
+, mpDoc( pDoc )
+, mpCurrentViewShellBase( nullptr )
+, mpFullScreenViewShellBase( nullptr )
+, mpFullScreenFrameView( nullptr )
+, mnInPlaceConfigEvent( nullptr )
+{
+}
+
+void SlideShow::ThrowIfDisposed() const
+{
+ if( mpDoc == nullptr )
+ throw DisposedException();
+}
+
+/// used by the model to create a slideshow for it
+rtl::Reference< SlideShow > SlideShow::Create( SdDrawDocument* pDoc )
+{
+ return new SlideShow( pDoc );
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( SdDrawDocument const * pDocument )
+{
+ rtl::Reference< SlideShow > xRet;
+
+ if( pDocument )
+ xRet = GetSlideShow( *pDocument );
+
+ return xRet;
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( SdDrawDocument const & rDocument )
+{
+ return rtl::Reference< SlideShow >(
+ dynamic_cast< SlideShow* >( rDocument.getPresentation().get() ) );
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( ViewShellBase const & rBase )
+{
+ return GetSlideShow( rBase.GetDocument() );
+}
+
+css::uno::Reference< css::presentation::XSlideShowController > SlideShow::GetSlideShowController(ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+
+ Reference< XSlideShowController > xRet;
+ if( xSlideShow.is() )
+ xRet = xSlideShow->getController();
+
+ return xRet;
+}
+
+bool SlideShow::StartPreview( ViewShellBase const & rBase,
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ if( !xSlideShow.is() )
+ return false;
+
+ xSlideShow->startPreview( xDrawPage, xAnimationNode );
+ return true;
+}
+
+void SlideShow::Stop( ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ if( xSlideShow.is() )
+ xSlideShow->end();
+}
+
+bool SlideShow::IsRunning( ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ return xSlideShow.is() && xSlideShow->isRunning();
+}
+
+bool SlideShow::IsRunning( const ViewShell& rViewShell )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rViewShell.GetViewShellBase() ) );
+ return xSlideShow.is() && xSlideShow->isRunning() && (xSlideShow->mxController->getViewShell() == &rViewShell);
+}
+
+void SlideShow::CreateController( ViewShell* pViewSh, ::sd::View* pView, vcl::Window* pParentWindow )
+{
+ SAL_INFO_IF( !mxController.is(), "sd.slideshow", "sd::SlideShow::CreateController(), clean up old controller first!" );
+
+ Reference< XPresentation2 > xThis( this );
+
+ rtl::Reference<SlideshowImpl> xController (
+ new SlideshowImpl(xThis, pViewSh, pView, mpDoc, pParentWindow));
+
+ // Reset mbIsInStartup. From here mxController.is() is used to prevent
+ // multiple slide show instances for one document.
+ mxController = xController;
+ mbIsInStartup = false;
+
+}
+
+// XServiceInfo
+OUString SAL_CALL SlideShow::getImplementationName( )
+{
+ return "com.sun.star.comp.sd.SlideShow";
+}
+
+sal_Bool SAL_CALL SlideShow::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SlideShow::getSupportedServiceNames( )
+{
+ return { "com.sun.star.presentation.Presentation" };
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL SlideShow::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static Reference< XPropertySetInfo > xInfo = maPropSet.getPropertySetInfo();
+ return xInfo;
+ }
+
+void SAL_CALL SlideShow::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ sd::PresentationSettings& rPresSettings = mpDoc->getPresentationSettings();
+
+ const SfxItemPropertyMapEntry* pEntry = maPropSet.getPropertyMapEntry(aPropertyName);
+
+ if( pEntry && ((pEntry->nFlags & PropertyAttribute::READONLY) != 0) )
+ throw PropertyVetoException();
+
+ bool bValuesChanged = false;
+ bool bIllegalArgument = true;
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case ATTR_PRESENT_ALL:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbAll != bVal )
+ {
+ rPresSettings.mbAll = bVal;
+ bValuesChanged = true;
+ if( bVal )
+ rPresSettings.mbCustomShow = false;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_CHANGE_PAGE:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( bVal == rPresSettings.mbLockedPages )
+ {
+ bValuesChanged = true;
+ rPresSettings.mbLockedPages = !bVal;
+ }
+ }
+ break;
+ }
+
+ case ATTR_PRESENT_ANIMATION_ALLOWED:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if(rPresSettings.mbAnimationAllowed != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbAnimationAllowed = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_CUSTOMSHOW:
+ {
+ OUString aShowName;
+ if( aValue >>= aShowName )
+ {
+ bIllegalArgument = false;
+
+ SdCustomShowList* pCustomShowList = mpDoc->GetCustomShowList();
+ if(pCustomShowList)
+ {
+ SdCustomShow* pCustomShow;
+ for( pCustomShow = pCustomShowList->First(); pCustomShow != nullptr; pCustomShow = pCustomShowList->Next() )
+ {
+ if( pCustomShow->GetName() == aShowName )
+ break;
+ }
+
+ rPresSettings.mbCustomShow = true;
+ bValuesChanged = true;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_ENDLESS:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbEndless != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbEndless = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_FULLSCREEN:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mbFullScreen != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbFullScreen = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_DIANAME:
+ {
+ OUString aPresPage;
+ aValue >>= aPresPage;
+ bIllegalArgument = false;
+ if( (rPresSettings.maPresPage != aPresPage) || !rPresSettings.mbCustomShow || !rPresSettings.mbAll )
+ {
+ bValuesChanged = true;
+ rPresSettings.maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
+ rPresSettings.mbCustomShow = false;
+ rPresSettings.mbAll = false;
+ }
+ break;
+ }
+ case ATTR_PRESENT_MANUEL:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbManual != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbManual = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_MOUSE:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mbMouseVisible != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbMouseVisible = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_ALWAYS_ON_TOP:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbAlwaysOnTop != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbAlwaysOnTop = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_NAVIGATOR:
+ bIllegalArgument = false;
+ //ignored, but exists in some older documents
+ break;
+ case ATTR_PRESENT_PEN:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if(rPresSettings.mbMouseAsPen != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbMouseAsPen = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_PAUSE_TIMEOUT:
+ {
+ sal_Int32 nValue = 0;
+ if( (aValue >>= nValue) && (nValue >= 0) )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mnPauseTimeout != nValue )
+ {
+ bValuesChanged = true;
+ rPresSettings.mnPauseTimeout = nValue;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_SHOW_PAUSELOGO:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbShowPauseLogo != bVal )
+ {
+ bValuesChanged = true;
+ rPresSettings.mbShowPauseLogo = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_DISPLAY:
+ {
+ sal_Int32 nDisplay = 0;
+ if( aValue >>= nDisplay )
+ {
+ bIllegalArgument = false;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ pOptions->SetDisplay( nDisplay );
+
+ FullScreenWorkWindow *pWin = dynamic_cast<FullScreenWorkWindow *>(GetWorkWindow());
+ if( !pWin )
+ return;
+ pWin->Restart(true);
+ }
+ break;
+ }
+
+ default:
+ throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( bIllegalArgument )
+ throw IllegalArgumentException();
+
+ if( bValuesChanged )
+ mpDoc->SetChanged();
+}
+
+Any SAL_CALL SlideShow::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ const sd::PresentationSettings& rPresSettings = mpDoc->getPresentationSettings();
+
+ const SfxItemPropertyMapEntry* pEntry = maPropSet.getPropertyMapEntry(PropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case ATTR_PRESENT_ALL:
+ return Any( !rPresSettings.mbCustomShow && rPresSettings.mbAll );
+ case ATTR_PRESENT_CHANGE_PAGE:
+ return Any( !rPresSettings.mbLockedPages );
+ case ATTR_PRESENT_ANIMATION_ALLOWED:
+ return Any( rPresSettings.mbAnimationAllowed );
+ case ATTR_PRESENT_CUSTOMSHOW:
+ {
+ SdCustomShowList* pList = mpDoc->GetCustomShowList();
+ SdCustomShow* pShow = (pList && rPresSettings.mbCustomShow) ? pList->GetCurObject() : nullptr;
+ OUString aShowName;
+
+ if(pShow)
+ aShowName = pShow->GetName();
+
+ return Any( aShowName );
+ }
+ case ATTR_PRESENT_ENDLESS:
+ return Any( rPresSettings.mbEndless );
+ case ATTR_PRESENT_FULLSCREEN:
+ return Any( rPresSettings.mbFullScreen );
+ case ATTR_PRESENT_DIANAME:
+ {
+ OUString aSlideName;
+
+ if( !rPresSettings.mbCustomShow && !rPresSettings.mbAll )
+ aSlideName = getPageApiNameFromUiName( rPresSettings.maPresPage );
+
+ return Any( aSlideName );
+ }
+ case ATTR_PRESENT_MANUEL:
+ return Any( rPresSettings.mbManual );
+ case ATTR_PRESENT_MOUSE:
+ return Any( rPresSettings.mbMouseVisible );
+ case ATTR_PRESENT_ALWAYS_ON_TOP:
+ return Any( rPresSettings.mbAlwaysOnTop );
+ case ATTR_PRESENT_NAVIGATOR:
+ return Any( false );
+ case ATTR_PRESENT_PEN:
+ return Any( rPresSettings.mbMouseAsPen );
+ case ATTR_PRESENT_PAUSE_TIMEOUT:
+ return Any( rPresSettings.mnPauseTimeout );
+ case ATTR_PRESENT_SHOW_PAUSELOGO:
+ return Any( rPresSettings.mbShowPauseLogo );
+ case ATTR_PRESENT_DISPLAY:
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ return Any(pOptions->GetDisplay());
+ }
+
+ default:
+ throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+void SAL_CALL SlideShow::addPropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::removePropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::addVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::removeVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& )
+{
+}
+
+// XPresentation
+
+void SAL_CALL SlideShow::start()
+{
+ const Sequence< PropertyValue > aArguments;
+ startWithArguments( aArguments );
+}
+
+WorkWindow *SlideShow::GetWorkWindow()
+{
+ if( !mpFullScreenViewShellBase )
+ return nullptr;
+
+ PresentationViewShell* pShell = dynamic_cast<PresentationViewShell*>(mpFullScreenViewShellBase->GetMainViewShell().get());
+
+ if( !pShell || !pShell->GetViewFrame() )
+ return nullptr;
+
+ return dynamic_cast<WorkWindow*>(pShell->GetViewFrame()->GetFrame().GetWindow().GetParent());
+}
+
+bool SlideShow::IsExitAfterPresenting() const
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+ return mpDoc->IsExitAfterPresenting();
+}
+
+void SlideShow::SetExitAfterPresenting(bool bExit)
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+ mpDoc->SetExitAfterPresenting(bExit);
+}
+
+void SAL_CALL SlideShow::end()
+{
+ SolarMutexGuard aGuard;
+
+ // The mbIsInStartup flag should have been reset during the start of the
+ // slide show. Reset it here just in case that something has horribly
+ // gone wrong.
+ assert(!mbIsInStartup);
+
+ rtl::Reference< SlideshowImpl > xController( mxController );
+ if( !xController.is() )
+ return;
+
+ mxController.clear();
+
+ if( mpFullScreenFrameView )
+ {
+ delete mpFullScreenFrameView;
+ mpFullScreenFrameView = nullptr;
+ }
+
+ ViewShellBase* pFullScreenViewShellBase = mpFullScreenViewShellBase;
+ mpFullScreenViewShellBase = nullptr;
+
+ // dispose before fullscreen window changes screens
+ // (potentially). If this needs to be moved behind
+ // pWorkWindow->StartPresentationMode() again, read issue
+ // pWorkWindow->i94007 & implement the solution outlined
+ // there.
+ xController->dispose();
+
+ if( pFullScreenViewShellBase )
+ {
+ PresentationViewShell* pShell = dynamic_cast<PresentationViewShell*>(pFullScreenViewShellBase->GetMainViewShell().get());
+
+ if( pShell && pShell->GetViewFrame() )
+ {
+ WorkWindow* pWorkWindow = dynamic_cast<WorkWindow*>(pShell->GetViewFrame()->GetFrame().GetWindow().GetParent());
+ if( pWorkWindow )
+ {
+ pWorkWindow->StartPresentationMode( (mxController.is() && mxController->maPresSettings.mbAlwaysOnTop)
+ ? PresentationFlags::HideAllApps : PresentationFlags::NONE );
+ }
+ }
+ }
+
+ if( pFullScreenViewShellBase )
+ {
+ PresentationViewShell* pShell = nullptr;
+ {
+ // Get the shell pointer in its own scope to be sure that
+ // the shared_ptr to the shell is released before DoClose()
+ // is called.
+ ::std::shared_ptr<ViewShell> pSharedView (pFullScreenViewShellBase->GetMainViewShell());
+ pShell = dynamic_cast<PresentationViewShell*>(pSharedView.get());
+ }
+ if( pShell && pShell->GetViewFrame() )
+ pShell->GetViewFrame()->DoClose();
+ }
+ else if( mpCurrentViewShellBase )
+ {
+ ViewShell* pViewShell = mpCurrentViewShellBase->GetMainViewShell().get();
+
+ if( pViewShell )
+ {
+ FrameView* pFrameView = pViewShell->GetFrameView();
+
+ if( pFrameView && (pFrameView->GetPresentationViewShellId() != SID_VIEWSHELL0) )
+ {
+ ViewShell::ShellType ePreviousType (pFrameView->GetPreviousViewShellType());
+ pFrameView->SetPreviousViewShellType(ViewShell::ST_NONE);
+
+ pFrameView->SetPresentationViewShellId(SID_VIEWSHELL0);
+ pFrameView->SetPreviousViewShellType(pViewShell->GetShellType());
+
+ framework::FrameworkHelper::Instance(*mpCurrentViewShellBase)->RequestView(
+ framework::FrameworkHelper::GetViewURL(ePreviousType),
+ framework::FrameworkHelper::msCenterPaneURL);
+
+ pViewShell->GetViewFrame()->GetBindings().InvalidateAll( true );
+ }
+ }
+ }
+
+ if( mpCurrentViewShellBase )
+ {
+ if (ViewShell* const pViewShell = mpCurrentViewShellBase->GetMainViewShell().get())
+ {
+ // invalidate the view shell so the presentation slot will be re-enabled
+ // and the rehearsing will be updated
+ pViewShell->Invalidate();
+
+ if( xController->meAnimationMode ==ANIMATIONMODE_SHOW )
+ {
+ // switch to the previously visible Slide
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>( pViewShell );
+ if( pDrawViewShell )
+ pDrawViewShell->SwitchPage( static_cast<sal_uInt16>(xController->getRestoreSlide()) );
+ else
+ {
+ DrawController& rDrawController =
+ *mpCurrentViewShellBase->GetDrawController();
+ rDrawController.setCurrentPage(
+ Reference<XDrawPage>(
+ mpDoc->GetSdPage(xController->getRestoreSlide(), PageKind::Standard)->getUnoPage(),
+ UNO_QUERY));
+ }
+ }
+
+ if( pViewShell->GetDoc()->IsExitAfterPresenting() )
+ {
+ pViewShell->GetDoc()->SetExitAfterPresenting( false );
+
+ Reference<frame::XDispatchProvider> xProvider(pViewShell->GetViewShellBase().GetController()->getFrame(),
+ UNO_QUERY);
+ if( xProvider.is() )
+ {
+ util::URL aURL;
+ aURL.Complete = ".uno:CloseFrame";
+
+ uno::Reference< frame::XDispatch > xDispatch(
+ xProvider->queryDispatch(
+ aURL, OUString(), 0));
+ if( xDispatch.is() )
+ {
+ xDispatch->dispatch(aURL,
+ uno::Sequence< beans::PropertyValue >());
+ }
+ }
+ }
+
+ // In case mbMouseAsPen was set, a new layer DrawnInSlideshow might have been generated
+ // during slideshow, which is not known to FrameView yet.
+ if (any2bool(getPropertyValue("UsePen"))
+ && pViewShell->GetDoc()->GetLayerAdmin().GetLayer("DrawnInSlideshow"))
+ {
+ SdrLayerIDSet aDocLayerIDSet;
+ pViewShell->GetDoc()->GetLayerAdmin().getVisibleLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetVisibleLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetVisibleLayers(aDocLayerIDSet);
+ }
+ pViewShell->GetDoc()->GetLayerAdmin().getPrintableLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetPrintableLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetPrintableLayers(aDocLayerIDSet);
+ }
+ pViewShell->GetDoc()->GetLayerAdmin().getLockedLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetLockedLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetLockedLayers(aDocLayerIDSet);
+ }
+ pViewShell->InvalidateWindows();
+ }
+
+ // Fire the acc focus event when focus is switched back. The above method
+ // mpCurrentViewShellBase->GetWindow()->GrabFocus() will set focus to WorkWindow
+ // instead of the sd::window, so here call Shell's method to fire the focus event
+ pViewShell->SwitchActiveViewFireFocus();
+ }
+ }
+ mpCurrentViewShellBase = nullptr;
+}
+
+void SAL_CALL SlideShow::rehearseTimings()
+{
+ Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue("RehearseTimings", true) };
+ startWithArguments( aArguments );
+}
+
+// XPresentation2
+
+void SAL_CALL SlideShow::startWithArguments(const Sequence< PropertyValue >& rArguments)
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ // Stop a running show before starting a new one.
+ if( mxController.is() )
+ {
+ assert(!mbIsInStartup);
+ end();
+ }
+ else if (mbIsInStartup)
+ {
+ // We are already somewhere in process of starting a slide show but
+ // have not yet got to the point where mxController is set. There
+ // is not yet a slide show to end so return silently.
+ return;
+ }
+
+ // Prevent multiple instance of the SlideShow class for one document.
+ mbIsInStartup = true;
+
+ mxCurrentSettings = std::make_shared<PresentationSettingsEx>( mpDoc->getPresentationSettings() );
+ mxCurrentSettings->SetArguments( rArguments );
+
+ // if there is no view shell base set, use the current one or the first using this document
+ if( mpCurrentViewShellBase == nullptr )
+ {
+ // first check current
+ ::sd::ViewShellBase* pBase = ::sd::ViewShellBase::GetViewShellBase( SfxViewFrame::Current() );
+ if( pBase && pBase->GetDocument() == mpDoc )
+ {
+ mpCurrentViewShellBase = pBase;
+ }
+ else
+ {
+ // current is not ours, so get first from ours
+ mpCurrentViewShellBase = ::sd::ViewShellBase::GetViewShellBase( SfxViewFrame::GetFirst( mpDoc->GetDocSh() ) );
+ }
+ }
+
+ // #i118456# make sure TextEdit changes get pushed to model.
+ // mpDrawView is tested against NULL above already.
+ if(mpCurrentViewShellBase)
+ {
+ ViewShell* pViewShell = mpCurrentViewShellBase->GetMainViewShell().get();
+
+ if(pViewShell && pViewShell->GetView())
+ {
+ pViewShell->GetView()->SdrEndTextEdit();
+ }
+ }
+
+ // Start either a full-screen or an in-place show.
+ if(mxCurrentSettings->mbFullScreen && !mxCurrentSettings->mbPreview)
+ StartFullscreenPresentation();
+ else
+ StartInPlacePresentation();
+
+}
+
+sal_Bool SAL_CALL SlideShow::isRunning( )
+{
+ SolarMutexGuard aGuard;
+ return mxController.is() && mxController->isRunning();
+}
+
+Reference< XSlideShowController > SAL_CALL SlideShow::getController( )
+{
+ ThrowIfDisposed();
+
+ return mxController;
+}
+
+// XComponent
+
+void SlideShow::disposing(std::unique_lock<std::mutex>&)
+{
+ SolarMutexGuard aGuard;
+
+ if( mnInPlaceConfigEvent )
+ {
+ Application::RemoveUserEvent( mnInPlaceConfigEvent );
+ mnInPlaceConfigEvent = nullptr;
+ }
+
+ if( mxController.is() )
+ {
+ mxController->dispose();
+ mxController.clear();
+ }
+
+ mpCurrentViewShellBase = nullptr;
+ mpFullScreenViewShellBase = nullptr;
+ mpDoc = nullptr;
+}
+
+void SlideShow::startPreview( const Reference< XDrawPage >& xDrawPage, const Reference< XAnimationNode >& xAnimationNode )
+{
+ Sequence< PropertyValue > aArguments{
+ comphelper::makePropertyValue("Preview", true),
+ comphelper::makePropertyValue("FirstPage", xDrawPage),
+ comphelper::makePropertyValue("AnimationNode", xAnimationNode),
+ comphelper::makePropertyValue("ParentWindow", Reference< XWindow >()),
+ };
+
+ startWithArguments( aArguments );
+}
+
+OutputDevice* SlideShow::getShowWindow()
+{
+ return mxController.is() ? mxController->mpShowWindow->GetOutDev() : nullptr;
+}
+
+int SlideShow::getAnimationMode() const
+{
+ return mxController.is() ? mxController->meAnimationMode : ANIMATIONMODE_SHOW;
+}
+
+void SlideShow::jumpToPageIndex( sal_Int32 nPageIndex )
+{
+ if( mxController.is() )
+ mxController->displaySlideIndex( nPageIndex );
+}
+
+void SlideShow::jumpToPageNumber( sal_Int32 nPageNumber )
+{
+ if( mxController.is() )
+ mxController->displaySlideNumber( nPageNumber );
+}
+
+sal_Int32 SlideShow::getCurrentPageNumber() const
+{
+ return mxController.is() ? mxController->getCurrentSlideNumber() : 0;
+}
+
+void SlideShow::jumpToBookmark( const OUString& sBookmark )
+{
+ if( mxController.is() )
+ mxController->jumpToBookmark( sBookmark );
+}
+
+bool SlideShow::isFullScreen() const
+{
+ return mxController.is() && mxController->maPresSettings.mbFullScreen;
+}
+
+void SlideShow::resize( const Size &rSize )
+{
+ if( mxController.is() )
+ mxController->resize( rSize );
+}
+
+bool SlideShow::activate( ViewShellBase& rBase )
+{
+ if( (mpFullScreenViewShellBase == &rBase) && !mxController.is() )
+ {
+ ::std::shared_ptr<PresentationViewShell> pShell = std::dynamic_pointer_cast<PresentationViewShell>(rBase.GetMainViewShell());
+ if (pShell != nullptr)
+ {
+ pShell->FinishInitialization( mpFullScreenFrameView );
+ mpFullScreenFrameView = nullptr;
+
+ CreateController( pShell.get(), pShell->GetView(), rBase.GetViewWindow() );
+
+ if (!mxController->startShow(mxCurrentSettings.get()))
+ return false;
+
+ pShell->Resize();
+ // Defer the sd::ShowWindow's GrabFocus to here. so that the accessible event can be fired correctly.
+ pShell->GetActiveWindow()->GrabFocus();
+ }
+ }
+
+ if( mxController.is() )
+ mxController->activate();
+
+ return true;
+}
+
+void SlideShow::deactivate()
+{
+ mxController->deactivate();
+}
+
+bool SlideShow::keyInput(const KeyEvent& rKEvt)
+{
+ return mxController.is() && mxController->keyInput(rKEvt);
+}
+
+void SlideShow::paint()
+{
+ if( mxController.is() )
+ mxController->paint();
+}
+
+void SlideShow::pause( bool bPause )
+{
+ if( mxController.is() )
+ {
+ if( bPause )
+ mxController->pause();
+ else
+ mxController->resume();
+ }
+}
+
+bool SlideShow::swipe(const CommandGestureSwipeData& rSwipeData)
+{
+ return mxController.is() && mxController->swipe(rSwipeData);
+}
+
+bool SlideShow::longpress(const CommandGestureLongPressData& rLongPressData)
+{
+ return mxController.is() && mxController->longpress(rLongPressData);
+}
+
+void SlideShow::StartInPlacePresentationConfigurationCallback()
+{
+ if( mnInPlaceConfigEvent != nullptr )
+ Application::RemoveUserEvent( mnInPlaceConfigEvent );
+
+ mnInPlaceConfigEvent = Application::PostUserEvent( LINK( this, SlideShow, StartInPlacePresentationConfigurationHdl ) );
+}
+
+IMPL_LINK_NOARG(SlideShow, StartInPlacePresentationConfigurationHdl, void*, void)
+{
+ mnInPlaceConfigEvent = nullptr;
+ StartInPlacePresentation();
+}
+
+void SlideShow::StartInPlacePresentation()
+{
+ if( mpCurrentViewShellBase )
+ {
+ // Save the current view shell type so that it can be restored after the
+ // show has ended. If there already is a saved shell type then that is
+ // not overwritten.
+
+ ViewShell::ShellType eShell = ViewShell::ST_NONE;
+
+ ::std::shared_ptr<FrameworkHelper> pHelper(FrameworkHelper::Instance(*mpCurrentViewShellBase));
+ ::std::shared_ptr<ViewShell> pMainViewShell(pHelper->GetViewShell(FrameworkHelper::msCenterPaneURL));
+
+ if( pMainViewShell )
+ eShell = pMainViewShell->GetShellType();
+
+ if( eShell != ViewShell::ST_IMPRESS )
+ {
+ // Switch temporary to a DrawViewShell which supports the in-place presentation.
+
+ if( pMainViewShell )
+ {
+ FrameView* pFrameView = pMainViewShell->GetFrameView();
+ pFrameView->SetPresentationViewShellId(SID_VIEWSHELL1);
+ pFrameView->SetPreviousViewShellType (pMainViewShell->GetShellType());
+ pFrameView->SetPageKind (PageKind::Standard);
+ }
+
+ pHelper->RequestView( FrameworkHelper::msImpressViewURL, FrameworkHelper::msCenterPaneURL );
+ pHelper->RunOnConfigurationEvent(
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ [this] (bool const) { return this->StartInPlacePresentationConfigurationCallback(); } );
+ return;
+ }
+ else
+ {
+ vcl::Window* pParentWindow = mxCurrentSettings->mpParentWindow;
+ if( pParentWindow == nullptr )
+ pParentWindow = mpCurrentViewShellBase->GetViewWindow();
+
+ CreateController( pMainViewShell.get(), pMainViewShell->GetView(), pParentWindow );
+ }
+ }
+ else if( mxCurrentSettings->mpParentWindow )
+ {
+ // no current view shell, but parent window
+ CreateController( nullptr, nullptr, mxCurrentSettings->mpParentWindow );
+ }
+
+ if( !mxController.is() )
+ return;
+
+ bool bSuccess = false;
+ if( mxCurrentSettings && mxCurrentSettings->mbPreview )
+ {
+ bSuccess = mxController->startPreview(mxCurrentSettings->mxStartPage, mxCurrentSettings->mxAnimationNode, mxCurrentSettings->mpParentWindow );
+ }
+ else
+ {
+ bSuccess = mxController->startShow(mxCurrentSettings.get());
+ }
+
+ if( !bSuccess )
+ end();
+ else
+ {
+ if( mpCurrentViewShellBase && ( !mxCurrentSettings || ( mxCurrentSettings && !mxCurrentSettings->mbPreview ) ) )
+ mpCurrentViewShellBase->GetWindow()->GrabFocus();
+ }
+}
+
+void SlideShow::StartFullscreenPresentation( )
+{
+ // Create the top level window in which the PresentationViewShell(Base)
+ // will be created. This is done here explicitly so that we can make it
+ // fullscreen.
+ const sal_Int32 nDisplay (GetDisplay());
+ VclPtr<WorkWindow> pWorkWindow = VclPtr<FullScreenWorkWindow>::Create(this, mpCurrentViewShellBase);
+ pWorkWindow->SetBackground(Wallpaper(COL_BLACK));
+ OUString Title(SdResId(STR_FULLSCREEN_SLIDESHOW));
+ Title = Title.replaceFirst("%s",
+ mpCurrentViewShellBase->GetDocShell()->GetTitle(SFX_TITLE_DETECT));
+ pWorkWindow->SetText(Title);
+ pWorkWindow->StartPresentationMode( true, mpDoc->getPresentationSettings().mbAlwaysOnTop ? PresentationFlags::HideAllApps : PresentationFlags::NONE, nDisplay);
+ // pWorkWindow->ShowFullScreenMode(sal_False, nDisplay);
+
+ if (!pWorkWindow->IsVisible())
+ return;
+
+ // Initialize the new presentation view shell with a copy of the
+ // frame view of the current view shell. This avoids that
+ // changes made by the presentation have an effect on the other
+ // view shells.
+ FrameView* pOriginalFrameView = nullptr;
+ ::std::shared_ptr<ViewShell> xShell(mpCurrentViewShellBase->GetMainViewShell());
+ if (xShell)
+ pOriginalFrameView = xShell->GetFrameView();
+
+ delete mpFullScreenFrameView;
+ mpFullScreenFrameView = new FrameView(mpDoc, pOriginalFrameView);
+
+ // The new frame is created hidden. To make it visible and activate the
+ // new view shell--a prerequisite to process slot calls and initialize
+ // its panes--a GrabFocus() has to be called later on.
+ SfxFrame* pNewFrame = SfxFrame::CreateHidden( *mpDoc->GetDocSh(), *pWorkWindow, PRESENTATION_FACTORY_ID );
+ pNewFrame->SetPresentationMode(true);
+
+ mpFullScreenViewShellBase = static_cast<ViewShellBase*>(pNewFrame->GetCurrentViewFrame()->GetViewShell());
+ if(mpFullScreenViewShellBase != nullptr)
+ {
+ // The following GrabFocus() is responsible for activating the
+ // new view shell. Without it the screen remains blank (under
+ // Windows and some Linux variants.)
+ mpFullScreenViewShellBase->GetWindow()->GrabFocus();
+ }
+}
+
+/// convert configuration setting display concept to real screens
+sal_Int32 SlideShow::GetDisplay()
+{
+ sal_Int32 nDisplay = 0;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ if( pOptions )
+ nDisplay = pOptions->GetDisplay();
+
+ if( nDisplay < 0 )
+ nDisplay = -1;
+ else if( nDisplay == 0)
+ nDisplay = static_cast<sal_Int32>(Application::GetDisplayExternalScreen());
+ else
+ nDisplay--;
+
+ SAL_INFO("sd", "Presenting on real screen " << nDisplay);
+
+ return nDisplay;
+}
+
+bool SlideShow::dependsOn( ViewShellBase const * pViewShellBase )
+{
+ return mxController.is() && (pViewShellBase == mpCurrentViewShellBase) && mpFullScreenViewShellBase;
+}
+
+Reference< presentation::XPresentation2 > CreatePresentation( const SdDrawDocument& rDocument )
+{
+ return Reference< presentation::XPresentation2 >( SlideShow::Create( const_cast< SdDrawDocument* >( &rDocument ) ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx
new file mode 100644
index 0000000000..4bf43fc3bd
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowimpl.cxx
@@ -0,0 +1,3619 @@
+/* -*- 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 <sal/config.h>
+
+#include <algorithm>
+
+#include <config_features.h>
+
+#include <com/sun/star/frame/theAutoRecovery.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/presentation/SlideShow.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <officecfg/Office/Impress.hxx>
+#include <officecfg/Office/Recovery.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urihelper.hxx>
+#include <basic/sbstar.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <sfx2/infobar.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/hyperdlg.hxx>
+#include <svx/svxids.hrc>
+#include <svx/unoapi.hxx>
+#include <AnimationChildWindow.hxx>
+#include <notifydocumentevent.hxx>
+#include "slideshowimpl.hxx"
+#include "slideshowviewimpl.hxx"
+#include "PaneHider.hxx"
+
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <utility>
+#include <vcl/canvastools.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <rtl/ref.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svtools/colrdlg.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include <PresentationViewShell.hxx>
+#include <RemoteServer.hxx>
+#include <customshowlist.hxx>
+#include <unopage.hxx>
+#include <sdpage.hxx>
+#include <sdmod.hxx>
+#include <app.hrc>
+#include <cusshow.hxx>
+#include <optsitem.hxx>
+
+#define CM_SLIDES 21
+
+using ::com::sun::star::animations::XAnimationNode;
+using ::com::sun::star::animations::XAnimationListener;
+using ::com::sun::star::awt::XWindow;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::beans;
+
+namespace sd
+{
+/** Slots, which will be disabled in the slide show and are managed by Sfx.
+ Have to be sorted in the order of the SIDs */
+sal_uInt16 const pAllowed[] =
+{
+ SID_OPENDOC , // 5501 ///< that internally jumps work
+ SID_JUMPTOMARK , // 5598
+ SID_OPENHYPERLINK , // 6676
+ SID_PRESENTATION_END // 27218
+};
+
+class AnimationSlideController
+{
+public:
+ enum Mode { ALL, FROM, CUSTOM, PREVIEW };
+
+public:
+ AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode );
+
+ void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; }
+ sal_Int32 getStartSlideIndex() const;
+
+ sal_Int32 getCurrentSlideNumber() const;
+ sal_Int32 getCurrentSlideIndex() const;
+
+ sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); }
+ sal_Int32 getSlideNumberCount() const { return mnSlideCount; }
+
+ sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const;
+
+ void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true );
+ void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode );
+
+ bool jumpToSlideIndex( sal_Int32 nNewSlideIndex );
+ bool jumpToSlideNumber( sal_Int32 nNewSlideIndex );
+
+ bool nextSlide();
+ bool previousSlide();
+
+ void displayCurrentSlide( const Reference< XSlideShow >& xShow,
+ const Reference< XDrawPagesSupplier>& xDrawPages,
+ const bool bSkipAllMainSequenceEffects );
+
+ sal_Int32 getNextSlideIndex() const;
+ sal_Int32 getPreviousSlideIndex() const;
+
+ bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const;
+
+ Reference< XDrawPage > getSlideByNumber( sal_Int32 nSlideNumber ) const;
+
+ sal_Int32 getNextSlideNumber() const;
+
+ bool hasSlides() const { return !maSlideNumbers.empty(); }
+
+private:
+ bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
+ sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;
+
+ bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (o3tl::make_unsigned(nIndex) < maSlideNumbers.size()); }
+ bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); }
+
+private:
+ Mode meMode;
+ sal_Int32 mnStartSlideNumber;
+ std::vector< sal_Int32 > maSlideNumbers;
+ std::vector< bool > maSlideVisible;
+ std::vector< bool > maSlideVisited;
+ Reference< XAnimationNode > mxPreviewNode;
+ sal_Int32 mnSlideCount;
+ sal_Int32 mnCurrentSlideIndex;
+ sal_Int32 mnHiddenSlideNumber;
+ Reference< XIndexAccess > mxSlides;
+};
+
+Reference< XDrawPage > AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber ) const
+{
+ Reference< XDrawPage > xSlide;
+ if( mxSlides.is() && (nSlideNumber >= 0) && (nSlideNumber < mxSlides->getCount()) )
+ mxSlides->getByIndex( nSlideNumber ) >>= xSlide;
+ return xSlide;
+}
+
+bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const
+{
+ sal_Int32 nIndex = findSlideIndex( nSlideNumber );
+
+ if( nIndex != -1 )
+ return maSlideVisible[ nIndex ];
+ else
+ return false;
+}
+
+void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode )
+{
+ mxPreviewNode = xPreviewNode;
+}
+
+AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode )
+: meMode( eMode )
+, mnStartSlideNumber(-1)
+, mnSlideCount( 0 )
+, mnCurrentSlideIndex(0)
+, mnHiddenSlideNumber( -1 )
+, mxSlides( xSlides )
+{
+ if( mxSlides.is() )
+ mnSlideCount = xSlides->getCount();
+}
+
+sal_Int32 AnimationSlideController::getStartSlideIndex() const
+{
+ if( mnStartSlideNumber >= 0 )
+ {
+ sal_Int32 nIndex;
+ const sal_Int32 nCount = maSlideNumbers.size();
+
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if( maSlideNumbers[nIndex] == mnStartSlideNumber )
+ return nIndex;
+ }
+ }
+
+ return 0;
+}
+
+sal_Int32 AnimationSlideController::getCurrentSlideNumber() const
+{
+ if( mnHiddenSlideNumber != -1 )
+ return mnHiddenSlideNumber;
+ else if( !maSlideNumbers.empty() )
+ return maSlideNumbers[mnCurrentSlideIndex];
+ else
+ return 0;
+}
+
+sal_Int32 AnimationSlideController::getCurrentSlideIndex() const
+{
+ if( mnHiddenSlideNumber != -1 )
+ return -1;
+ else
+ return mnCurrentSlideIndex;
+}
+
+bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex )
+{
+ if( isValidIndex( nNewSlideIndex ) )
+ {
+ mnCurrentSlideIndex = nNewSlideIndex;
+ mnHiddenSlideNumber = -1;
+ maSlideVisited[mnCurrentSlideIndex] = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber )
+{
+ sal_Int32 nIndex = findSlideIndex( nNewSlideNumber );
+ if( isValidIndex( nIndex ) )
+ {
+ return jumpToSlideIndex( nIndex );
+ }
+ else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) )
+ {
+ // jump to a hidden slide
+ mnHiddenSlideNumber = nNewSlideNumber;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const
+{
+ if( isValidIndex( nSlideIndex ) )
+ return maSlideNumbers[nSlideIndex];
+ else
+ return -1;
+}
+
+void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ )
+{
+ DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
+ if( isValidSlideNumber( nSlideNumber ) )
+ {
+ maSlideNumbers.push_back( nSlideNumber );
+ maSlideVisible.push_back( bVisible );
+ maSlideVisited.push_back( false );
+ }
+}
+
+bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode )
+{
+ if( isValidSlideNumber( nSlideNumber ) ) try
+ {
+ xSlide.set( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW );
+
+ if( meMode == PREVIEW )
+ {
+ xAnimNode = mxPreviewNode;
+ }
+ else
+ {
+ Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW );
+ xAnimNode = xAnimNodeSupplier->getAnimationNode();
+ }
+
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" );
+ }
+
+ return false;
+}
+
+sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const
+{
+ sal_Int32 nIndex;
+ const sal_Int32 nCount = maSlideNumbers.size();
+
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if( maSlideNumbers[nIndex] == nSlideNumber )
+ return nIndex;
+ }
+
+ return -1;
+}
+
+sal_Int32 AnimationSlideController::getNextSlideIndex() const
+{
+ switch( meMode )
+ {
+ case ALL:
+ {
+ sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1;
+ if( isValidIndex( nNewSlideIndex ) )
+ {
+ // if the current slide is not excluded, make sure the
+ // next slide is also not excluded.
+ // if the current slide is excluded, we want to go
+ // to the next slide, even if this is also excluded.
+ if( maSlideVisible[mnCurrentSlideIndex] )
+ {
+ while( isValidIndex( nNewSlideIndex ) )
+ {
+ if( maSlideVisible[nNewSlideIndex] )
+ break;
+
+ nNewSlideIndex++;
+ }
+ }
+ }
+ return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1;
+ }
+
+ case FROM:
+ case CUSTOM:
+ return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex;
+
+ default:
+ case PREVIEW:
+ return -1;
+
+ }
+}
+
+sal_Int32 AnimationSlideController::getNextSlideNumber() const
+{
+ sal_Int32 nNextSlideIndex = getNextSlideIndex();
+ if( isValidIndex( nNextSlideIndex ) )
+ {
+ return maSlideNumbers[nNextSlideIndex];
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+bool AnimationSlideController::nextSlide()
+{
+ return jumpToSlideIndex( getNextSlideIndex() );
+}
+
+sal_Int32 AnimationSlideController::getPreviousSlideIndex() const
+{
+ sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1;
+
+ switch( meMode )
+ {
+ case ALL:
+ {
+ // make sure the previous slide is visible
+ // or was already visited
+ while( isValidIndex( nNewSlideIndex ) )
+ {
+ if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] )
+ break;
+
+ nNewSlideIndex--;
+ }
+
+ break;
+ }
+
+ case PREVIEW:
+ return -1;
+
+ default:
+ break;
+ }
+
+ return nNewSlideIndex;
+}
+
+bool AnimationSlideController::previousSlide()
+{
+ return jumpToSlideIndex( getPreviousSlideIndex() );
+}
+
+void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow,
+ const Reference< XDrawPagesSupplier>& xDrawPages,
+ const bool bSkipAllMainSequenceEffects )
+{
+ const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber();
+
+ if( !(xShow.is() && (nCurrentSlideNumber != -1 )) )
+ return;
+
+ Reference< XDrawPage > xSlide;
+ Reference< XAnimationNode > xAnimNode;
+ ::std::vector<PropertyValue> aProperties;
+
+ const sal_Int32 nNextSlideNumber = getNextSlideNumber();
+ if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode ) )
+ {
+ Sequence< Any > aValue{ Any(xSlide), Any(xAnimNode) };
+ aProperties.emplace_back( "Prefetch" ,
+ -1,
+ Any(aValue),
+ PropertyState_DIRECT_VALUE);
+ }
+ if (bSkipAllMainSequenceEffects)
+ {
+ // Add one property that prevents the slide transition from being
+ // shown (to speed up the transition to the previous slide) and
+ // one to show all main sequence effects so that the user can
+ // continue to undo effects.
+ aProperties.emplace_back( "SkipAllMainSequenceEffects",
+ -1,
+ Any(true),
+ PropertyState_DIRECT_VALUE);
+ aProperties.emplace_back("SkipSlideTransition",
+ -1,
+ Any(true),
+ PropertyState_DIRECT_VALUE);
+ }
+
+ if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) )
+ xShow->displaySlide( xSlide, xDrawPages, xAnimNode, comphelper::containerToSequence(aProperties) );
+}
+
+constexpr OUString gsOnClick( u"OnClick"_ustr );
+constexpr OUString gsBookmark( u"Bookmark"_ustr );
+constexpr OUString gsVerb( u"Verb"_ustr );
+
+SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow )
+: mxModel(pDoc->getUnoModel())
+, maUpdateTimer("SlideShowImpl maUpdateTimer")
+, maInputFreezeTimer("SlideShowImpl maInputFreezeTimer")
+, maDeactivateTimer("SlideShowImpl maDeactivateTimer")
+, mpView(pView)
+, mpViewShell(pViewSh)
+, mpDocSh(pDoc->GetDocSh())
+, mpDoc(pDoc)
+, mpParentWindow(pParentWindow)
+, mpShowWindow(nullptr)
+, mnRestoreSlide(0)
+, maPresSize( -1, -1 )
+, meAnimationMode(ANIMATIONMODE_SHOW)
+, mpOldActiveWindow(nullptr)
+, mnChildMask( 0 )
+, mbDisposed(false)
+, mbAutoSaveWasOn(false)
+, mbRehearseTimings(false)
+, mbIsPaused(false)
+, mbWasPaused(false)
+, mbInputFreeze(false)
+, mbActive(false)
+, maPresSettings( pDoc->getPresentationSettings() )
+, mnUserPaintColor( 0x80ff0000L )
+, mbUsePen(false)
+, mdUserPaintStrokeWidth ( 150.0 )
+, mnEndShowEvent(nullptr)
+, mnContextMenuEvent(nullptr)
+, mnEventObjectChange(nullptr)
+, mnEventPageOrderChange(nullptr)
+, mxPresentation( xPresentation )
+{
+ if( mpViewShell )
+ mpOldActiveWindow = mpViewShell->GetActiveWindow();
+
+ maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl));
+ // Priority must not be too high or we'll starve input handling etc.
+ maUpdateTimer.SetPriority(TaskPriority::REPAINT);
+
+ maDeactivateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, deactivateHdl));
+ maDeactivateTimer.SetTimeout( 20 );
+
+ maInputFreezeTimer.SetInvokeHandler( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) );
+ maInputFreezeTimer.SetTimeout( 20 );
+
+ // no autosave during show
+ if (officecfg::Office::Recovery::AutoSave::Enabled::get())
+ mbAutoSaveWasOn = true;
+
+ Application::AddEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
+
+ mbUsePen = maPresSettings.mbMouseAsPen;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ if( pOptions )
+ {
+ mnUserPaintColor = pOptions->GetPresentationPenColor();
+ mdUserPaintStrokeWidth = pOptions->GetPresentationPenWidth();
+ }
+
+ // to be able to react on various changes in the DrawModel, this class
+ // is now derived from SfxListener and registers itself at the DrawModel
+ if (nullptr != mpDoc)
+ StartListening(*mpDoc);
+}
+
+SlideshowImpl::~SlideshowImpl()
+{
+ // stop listening to DrawModel (see above)
+ if (nullptr != mpDoc)
+ EndListening(*mpDoc);
+
+ SdModule *pModule = SD_MOD();
+ //rhbz#806663 SlideshowImpl can outlive SdModule
+ SdOptions* pOptions = pModule ?
+ pModule->GetSdOptions(DocumentType::Impress) : nullptr;
+ if( pOptions )
+ {
+ pOptions->SetPresentationPenColor(mnUserPaintColor);
+ pOptions->SetPresentationPenWidth(mdUserPaintStrokeWidth);
+ }
+
+ Application::RemoveEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
+
+ maDeactivateTimer.Stop();
+
+ if( !mbDisposed )
+ {
+ OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
+ std::unique_lock g(m_aMutex);
+ disposing(g);
+ }
+}
+
+void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
+{
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::presentationStopped();
+#endif
+ if( mxShow.is() && mpDoc )
+ NotifyDocumentEvent(
+ *mpDoc,
+ "OnEndPresentation" );
+
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( true );
+
+ if( mnEndShowEvent )
+ Application::RemoveUserEvent( mnEndShowEvent );
+ if( mnContextMenuEvent )
+ Application::RemoveUserEvent( mnContextMenuEvent );
+ if( mnEventObjectChange )
+ Application::RemoveUserEvent( mnEventObjectChange );
+ if( mnEventPageOrderChange )
+ Application::RemoveUserEvent( mnEventPageOrderChange );
+
+ maInputFreezeTimer.Stop();
+
+ SolarMutexGuard aSolarGuard;
+
+ if( !mxShow.is() )
+ return;
+
+ if( mxPresentation.is() )
+ mxPresentation->end();
+
+ maUpdateTimer.Stop();
+
+ removeShapeEvents();
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->removeAsSlideShowListener();
+
+ try
+ {
+ if( mxView.is() )
+ mxShow->removeView( mxView );
+
+ Reference< XComponent > xComponent( mxShow, UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ if( mxView.is() )
+ mxView->dispose();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
+ }
+
+ mxShow.clear();
+ mxView.clear();
+ mxListenerProxy.clear();
+ mpSlideController.reset();
+
+ // take DrawView from presentation window, but give the old window back
+ if( mpShowWindow && mpView )
+ mpView->DeleteDeviceFromPaintView( *mpShowWindow->GetOutDev() );
+
+ if( mpView )
+ mpView->SetAnimationPause( false );
+
+ if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow(mpOldActiveWindow);
+ if (mpShowWindow)
+ mpShowWindow->SetViewShell( nullptr );
+ }
+
+ if( mpView )
+ mpView->InvalidateAllWin();
+
+ if( maPresSettings.mbFullScreen )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ // restore StarBASICErrorHdl
+ StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl);
+ maStarBASICGlobalErrorHdl = Link<StarBASIC*,bool>();
+#endif
+ }
+ else
+ {
+ if( mpShowWindow )
+ mpShowWindow->Hide();
+ }
+
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mpDocSh->SetSlotFilter();
+ mpDocSh->ApplySlotFilter();
+
+ Help::EnableContextHelp();
+ Help::EnableExtHelp();
+
+ showChildWindows();
+ mnChildMask = 0;
+ }
+
+ // show current window again
+ if( mpViewShell && dynamic_cast< PresentationViewShell *>( mpViewShell ) == nullptr)
+ {
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mpViewShell->GetViewShellBase().ShowUIControls (true);
+ mpPaneHider.reset();
+ }
+ else if( meAnimationMode == ANIMATIONMODE_PREVIEW )
+ {
+ mpViewShell->ShowUIControls(true);
+ }
+ }
+
+ if( mpShowWindow )
+ mpShowWindow->Hide();
+ mpShowWindow.disposeAndClear();
+
+ if ( mpViewShell )
+ {
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ ::sd::Window* pActWin = mpViewShell->GetActiveWindow();
+
+ if (pActWin)
+ {
+ Size aVisSizePixel = pActWin->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = pActWin->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ mpViewShell->VisAreaChanged(aVisAreaWin);
+ if (mpView)
+ mpView->VisAreaChanged(pActWin->GetOutDev());
+ pActWin->GrabFocus();
+ }
+ }
+
+ // restart the custom show dialog if he started us
+ if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
+ {
+ mpViewShell->SetStartShowWithDialog( false );
+ getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+
+ mpViewShell->GetViewShellBase().UpdateBorder(true);
+ }
+
+ if( mpShowWindow )
+ {
+ mpShowWindow.disposeAndClear();
+ }
+
+ setActiveXToolbarsVisible( true );
+
+ mbDisposed = true;
+}
+
+bool SlideshowImpl::startPreview(
+ const Reference< XDrawPage >& xDrawPage,
+ const Reference< XAnimationNode >& xAnimationNode,
+ vcl::Window * pParent )
+{
+ bool bRet = false;
+
+ try
+ {
+ const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY );
+ if (xServiceInfo.is()) {
+ const Sequence<OUString> supportedServices(
+ xServiceInfo->getSupportedServiceNames() );
+ if (comphelper::findValue(supportedServices, "com.sun.star.drawing.MasterPage") != -1) {
+ OSL_FAIL("sd::SlideshowImpl::startPreview() "
+ "not allowed on master page!");
+ return false;
+ }
+ }
+
+ mxPreviewDrawPage = xDrawPage;
+ mxPreviewAnimationNode = xAnimationNode;
+ meAnimationMode = ANIMATIONMODE_PREVIEW;
+
+ maPresSettings.mbAll = false;
+ maPresSettings.mbEndless = false;
+ maPresSettings.mbCustomShow = false;
+ maPresSettings.mbManual = false;
+ maPresSettings.mbMouseVisible = false;
+ maPresSettings.mbMouseAsPen = false;
+ maPresSettings.mbLockedPages = false;
+ maPresSettings.mbAlwaysOnTop = false;
+ maPresSettings.mbFullScreen = false;
+ maPresSettings.mbAnimationAllowed = true;
+ maPresSettings.mnPauseTimeout = 0;
+ maPresSettings.mbShowPauseLogo = false;
+
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+ mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
+
+ sal_Int32 nSlideNumber = 0;
+ Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW );
+ xSet->getPropertyValue( "Number" ) >>= nSlideNumber;
+ mpSlideController->insertSlideNumber( nSlideNumber-1 );
+ mpSlideController->setPreviewNode( xAnimationNode );
+
+ mpShowWindow = VclPtr<ShowWindow>::Create( this, ((pParent == nullptr) && mpViewShell) ? mpParentWindow.get() : pParent );
+ if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow( mpShowWindow );
+ mpShowWindow->SetViewShell (mpViewShell);
+ mpViewShell->ShowUIControls (false);
+ }
+
+ if( mpView )
+ {
+ mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev(), nullptr );
+ mpView->SetAnimationPause( true );
+ }
+
+ // call resize handler
+ if( pParent )
+ {
+ maPresSize = pParent->GetSizePixel();
+ }
+ else if( mpViewShell )
+ {
+ ::tools::Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle());
+ if (AllSettings::GetLayoutRTL())
+ {
+ aContentRect.SetLeft( aContentRect.Right() );
+ aContentRect.AdjustRight(aContentRect.Right() );
+ }
+ maPresSize = aContentRect.GetSize();
+ mpShowWindow->SetPosPixel( aContentRect.TopLeft() );
+ }
+ else
+ {
+ OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
+ }
+ resize( maPresSize );
+
+ sal_Int32 nPropertyCount = 1;
+ if( mxPreviewAnimationNode.is() )
+ nPropertyCount++;
+
+ Sequence< beans::PropertyValue > aProperties(nPropertyCount);
+ auto pProperties = aProperties.getArray();
+ pProperties[0].Name = "AutomaticAdvancement";
+ pProperties[0].Value <<= 1.0; // one second timeout
+
+ if( mxPreviewAnimationNode.is() )
+ {
+ pProperties[1].Name = "NoSlideTransitions";
+ pProperties[1].Value <<= true;
+ }
+
+ bRet = startShowImpl( aProperties );
+
+ if( mpShowWindow != nullptr && meAnimationMode == ANIMATIONMODE_PREVIEW )
+ mpShowWindow->SetPreviewMode();
+
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
+{
+ const rtl::Reference<SlideshowImpl> xKeepAlive(this);
+
+ DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" );
+ if( mxShow.is() )
+ return true;
+ DBG_ASSERT( mpParentWindow!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" );
+ if (mpParentWindow == nullptr)
+ return false;
+
+ // Autoplay (pps/ppsx)
+ if (mpViewShell->GetDoc()->IsStartWithPresentation()){
+ mpViewShell->GetDoc()->SetExitAfterPresenting(true);
+ }
+
+ bool bRet = false;
+
+ try
+ {
+ if( pPresSettings )
+ {
+ maPresSettings = *pPresSettings;
+ mbRehearseTimings = pPresSettings->mbRehearseTimings;
+ }
+
+ OUString aPresSlide( maPresSettings.maPresPage );
+ SdPage* pStartPage = mpViewShell->GetActualPage();
+ bool bStartWithActualSlide = pStartPage;
+
+ // times should be measured?
+ if( mbRehearseTimings )
+ {
+ maPresSettings.mbEndless = false;
+ maPresSettings.mbManual = true;
+ maPresSettings.mbMouseVisible = true;
+ maPresSettings.mbMouseAsPen = false;
+ maPresSettings.mnPauseTimeout = 0;
+ maPresSettings.mbShowPauseLogo = false;
+ }
+
+ if( pStartPage )
+ {
+ if( pStartPage->GetPageKind() == PageKind::Notes )
+ {
+ // we are in notes page mode, so get
+ // the corresponding draw page
+ const sal_uInt16 nPgNum = ( pStartPage->GetPageNum() - 2 ) >> 1;
+ pStartPage = mpDoc->GetSdPage( nPgNum, PageKind::Standard );
+ }
+ }
+
+ if( bStartWithActualSlide )
+ {
+ if ( aPresSlide.isEmpty())
+ {
+ // no preset slide yet, so pick current on one
+ aPresSlide = pStartPage->GetName();
+ // if the starting slide is hidden, we can't set slide controller to ALL mode
+ maPresSettings.mbAll = !pStartPage->IsExcluded();
+ }
+
+ if( meAnimationMode != ANIMATIONMODE_SHOW )
+ {
+ if( pStartPage->GetPageKind() == PageKind::Standard )
+ {
+ maPresSettings.mbAll = false;
+ }
+ }
+ }
+
+ // build page list
+ createSlideList( maPresSettings.mbAll, aPresSlide );
+
+ // remember Slide number from where the show was started
+ if( pStartPage )
+ mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;
+
+ if( mpSlideController->hasSlides() )
+ {
+ // hide child windows
+ hideChildWindows();
+
+ mpShowWindow = VclPtr<ShowWindow>::Create( this, mpParentWindow );
+ mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
+ mpViewShell->SetActiveWindow( mpShowWindow );
+ mpShowWindow->SetViewShell (mpViewShell);
+ mpViewShell->GetViewShellBase().ShowUIControls (false);
+ // Hide the side panes for in-place presentations.
+ if ( ! maPresSettings.mbFullScreen)
+ mpPaneHider.reset(new PaneHider(*mpViewShell,this));
+
+ // these Slots are forbidden in other views for this document
+ if( mpDocSh )
+ {
+ mpDocSh->SetSlotFilter( true, pAllowed );
+ mpDocSh->ApplySlotFilter();
+ }
+
+ Help::DisableContextHelp();
+ Help::DisableExtHelp();
+
+ if( maPresSettings.mbFullScreen )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ // disable basic ide error handling
+ maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl();
+ StarBASIC::SetGlobalErrorHdl( Link<StarBASIC*,bool>() );
+#endif
+ }
+
+ // call resize handler
+ maPresSize = mpParentWindow->GetSizePixel();
+ if (!maPresSettings.mbFullScreen)
+ {
+ const ::tools::Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle();
+ maPresSize = aClientRect.GetSize();
+ mpShowWindow->SetPosPixel( aClientRect.TopLeft() );
+ resize( maPresSize );
+ }
+
+ // #i41824#
+ // Note: In FullScreen Mode the OS (window manager) sends a resize to
+ // the WorkWindow once it actually resized it to full size. The
+ // WorkWindow propagates the resize to the DrawViewShell which calls
+ // resize() at the SlideShow (this). Calling resize here results in a
+ // temporary display of a black window in the window's default size
+
+ if( mpView )
+ {
+ mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev(), nullptr );
+ mpView->SetAnimationPause( true );
+ }
+
+ SfxBindings* pBindings = getBindings();
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_PRESENTATION );
+ pBindings->Invalidate( SID_REHEARSE_TIMINGS );
+ }
+
+ // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly.
+ //mpShowWindow->GrabFocus();
+
+ std::vector<beans::PropertyValue> aProperties;
+ aProperties.reserve( 4 );
+
+ aProperties.emplace_back( "AdvanceOnClick" ,
+ -1, Any( !maPresSettings.mbLockedPages ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "ImageAnimationsAllowed" ,
+ -1, Any( maPresSettings.mbAnimationAllowed ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ const bool bZOrderEnabled(
+ SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() );
+ aProperties.emplace_back( "DisableAnimationZOrder" ,
+ -1, Any( !bZOrderEnabled ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "ForceManualAdvance" ,
+ -1, Any( maPresSettings.mbManual ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ if( mbUsePen )
+ {
+ aProperties.emplace_back( "UserPaintColor" ,
+ // User paint color is black by default.
+ -1, Any( mnUserPaintColor ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "UserPaintStrokeWidth" ,
+ // User paint color is black by default.
+ -1, Any( mdUserPaintStrokeWidth ),
+ beans::PropertyState_DIRECT_VALUE );
+ }
+
+ if (mbRehearseTimings) {
+ aProperties.emplace_back( "RehearseTimings" ,
+ -1, Any(true), beans::PropertyState_DIRECT_VALUE );
+ }
+
+ bRet = startShowImpl( Sequence<beans::PropertyValue>(
+ aProperties.data(), aProperties.size() ) );
+
+ }
+
+ setActiveXToolbarsVisible( false );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties )
+{
+ try
+ {
+ mxShow.set( createSlideShow(), UNO_SET_THROW );
+
+ mxView = new SlideShowView(
+ *mpShowWindow,
+ mpDoc,
+ meAnimationMode,
+ this,
+ maPresSettings.mbFullScreen);
+
+ // try add wait symbol to properties:
+ const Reference<rendering::XSpriteCanvas> xSpriteCanvas(
+ mxView->getCanvas() );
+ if (xSpriteCanvas.is())
+ {
+ BitmapEx waitSymbolBitmap(BMP_WAIT_ICON);
+ const Reference<rendering::XBitmap> xBitmap(
+ vcl::unotools::xBitmapFromBitmapEx( waitSymbolBitmap ) );
+ if (xBitmap.is())
+ {
+ mxShow->setProperty(
+ beans::PropertyValue( "WaitSymbolBitmap" ,
+ -1,
+ Any( xBitmap ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+
+ BitmapEx pointerSymbolBitmap(BMP_POINTER_ICON);
+ const Reference<rendering::XBitmap> xPointerBitmap(
+ vcl::unotools::xBitmapFromBitmapEx( pointerSymbolBitmap ) );
+ if (xPointerBitmap.is())
+ {
+ mxShow->setProperty(
+ beans::PropertyValue( "PointerSymbolBitmap" ,
+ -1,
+ Any( xPointerBitmap ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+ if (officecfg::Office::Impress::Misc::Start::ShowNavigationPanel::get())
+ {
+ NavbarButtonSize btnScale = static_cast<NavbarButtonSize>(officecfg::Office::Impress::Layout::Display::NavigationBtnScale::get());
+ OUString prevSlidePath = "";
+ OUString nextSlidePath = "";
+ OUString menuPath = "";
+ switch (btnScale)
+ {
+ case NavbarButtonSize::Large:
+ {
+ prevSlidePath = BMP_PREV_SLIDE_LARGE;
+ nextSlidePath = BMP_NEXT_SLIDE_LARGE;
+ menuPath = BMP_MENU_SLIDE_LARGE;
+ break;
+ }
+ case NavbarButtonSize::XLarge:
+ {
+ prevSlidePath = BMP_PREV_SLIDE_EXTRALARGE;
+ nextSlidePath = BMP_NEXT_SLIDE_EXTRALARGE;
+ menuPath = BMP_MENU_SLIDE_EXTRALARGE;
+ break;
+ }
+ case NavbarButtonSize::Auto:
+ case NavbarButtonSize::Small:
+ default:
+ {
+ prevSlidePath = BMP_PREV_SLIDE_SMALL;
+ nextSlidePath = BMP_NEXT_SLIDE_SMALL;
+ menuPath = BMP_MENU_SLIDE_SMALL;
+ break;
+ }
+ }
+ BitmapEx prevSlideBm(prevSlidePath);
+ const Reference<rendering::XBitmap> xPrevSBitmap(
+ vcl::unotools::xBitmapFromBitmapEx(prevSlideBm));
+ if (xPrevSBitmap.is())
+ {
+ mxShow->setProperty(beans::PropertyValue("NavigationSlidePrev", -1,
+ Any(xPrevSBitmap),
+ beans::PropertyState_DIRECT_VALUE));
+ }
+ BitmapEx menuSlideBm(menuPath);
+ const Reference<rendering::XBitmap> xMenuSBitmap(
+ vcl::unotools::xBitmapFromBitmapEx(menuSlideBm));
+ if (xMenuSBitmap.is())
+ {
+ mxShow->setProperty(beans::PropertyValue("NavigationSlideMenu", -1,
+ Any(xMenuSBitmap),
+ beans::PropertyState_DIRECT_VALUE));
+ }
+ BitmapEx nextSlideBm(nextSlidePath);
+ const Reference<rendering::XBitmap> xNextSBitmap(
+ vcl::unotools::xBitmapFromBitmapEx(nextSlideBm));
+ if (xNextSBitmap.is())
+ {
+ mxShow->setProperty(beans::PropertyValue("NavigationSlideNext", -1,
+ Any(xNextSBitmap),
+ beans::PropertyState_DIRECT_VALUE));
+ }
+ }
+ }
+
+ for( const auto& rProp : aProperties )
+ mxShow->setProperty( rProp );
+
+ mxShow->addView( mxView );
+
+ mxListenerProxy.set( new SlideShowListenerProxy( this, mxShow ) );
+ mxListenerProxy->addAsSlideShowListener();
+
+ NotifyDocumentEvent(
+ *mpDoc,
+ "OnStartPresentation");
+ displaySlideIndex( mpSlideController->getStartSlideIndex() );
+
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" );
+ return false;
+ }
+}
+
+/** called only by the slideshow view when the first paint event occurs.
+ This actually starts the slideshow. */
+void SlideshowImpl::onFirstPaint()
+{
+ if( mpShowWindow )
+ {
+ /*
+ mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) );
+ mpShowWindow->Erase();
+ mpShowWindow->SetBackground();
+ */
+ }
+
+ SolarMutexGuard aSolarGuard;
+ maUpdateTimer.SetTimeout( sal_uLong(100) );
+ maUpdateTimer.Start();
+}
+
+void SlideshowImpl::paint()
+{
+ if( mxView.is() ) try
+ {
+ awt::PaintEvent aEvt;
+ // aEvt.UpdateRect = TODO
+ mxView->paint( aEvt );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::addSlideShowListener( const Reference< XSlideShowListener >& xListener )
+{
+ if( mxListenerProxy.is() )
+ mxListenerProxy->addSlideShowListener( xListener );
+}
+
+void SAL_CALL SlideshowImpl::removeSlideShowListener( const Reference< XSlideShowListener >& xListener )
+{
+ if( mxListenerProxy.is() )
+ mxListenerProxy->removeSlideShowListener( xListener );
+}
+
+void SlideshowImpl::slideEnded(const bool bReverse)
+{
+ if (bReverse)
+ gotoPreviousSlide(true);
+ else
+ gotoNextSlide();
+}
+
+bool SlideshowImpl::swipe(const CommandGestureSwipeData &rSwipeData)
+{
+ if (mbUsePen || mnContextMenuEvent)
+ return false;
+ double nVelocityX = rSwipeData.getVelocityX();
+ // tdf#108475 make it swipe only if some reasonable movement was involved
+ if (fabs(nVelocityX) < 50)
+ return false;
+ if (nVelocityX > 0)
+ {
+ gotoPreviousSlide();
+ }
+ else
+ {
+ gotoNextEffect();
+ }
+ //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted
+ //to the swipe instead
+ mxView->ignoreNextMouseReleased();
+ return true;
+}
+
+bool SlideshowImpl::longpress(const CommandGestureLongPressData &rLongPressData)
+{
+ if (mnContextMenuEvent)
+ return false;
+
+ maPopupMousePos = Point(rLongPressData.getX(), rLongPressData.getY());
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+
+ return true;
+}
+
+void SlideshowImpl::removeShapeEvents()
+{
+ if( !(mxShow.is() && mxListenerProxy.is()) )
+ return;
+
+ try
+ {
+ for( const auto& rEntry : maShapeEventMap )
+ {
+ mxListenerProxy->removeShapeEventListener( rEntry.first );
+ mxShow->setShapeCursor( rEntry.first, awt::SystemPointer::ARROW );
+ }
+
+ maShapeEventMap.clear();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber)
+{
+ if( nSlideNumber < 0 )
+ return;
+
+ try
+ {
+ Reference< XDrawPagesSupplier > xDrawPages( mxModel, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xPages( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+
+ Reference< XShapes > xDrawPage;
+ xPages->getByIndex(nSlideNumber) >>= xDrawPage;
+
+ if( xDrawPage.is() )
+ {
+ Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY );
+ if( xMasterPageTarget.is() )
+ {
+ Reference< XShapes > xMasterPage = xMasterPageTarget->getMasterPage();
+ if( xMasterPage.is() )
+ registerShapeEvents( xMasterPage );
+ }
+ registerShapeEvents( xDrawPage );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::registerShapeEvents( Reference< XShapes > const & xShapes )
+{
+ try
+ {
+ const sal_Int32 nShapeCount = xShapes->getCount();
+ sal_Int32 nShape;
+ for( nShape = 0; nShape < nShapeCount; nShape++ )
+ {
+ Reference< XShape > xShape;
+ xShapes->getByIndex( nShape ) >>= xShape;
+
+ if( xShape.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
+ {
+ Reference< XShapes > xSubShapes( xShape, UNO_QUERY );
+ if( xSubShapes.is() )
+ registerShapeEvents( xSubShapes );
+ }
+
+ Reference< XPropertySet > xSet( xShape, UNO_QUERY );
+ if( !xSet.is() )
+ continue;
+
+ Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
+ if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( gsOnClick ) )
+ continue;
+
+ WrappedShapeEventImplPtr pEvent = std::make_shared<WrappedShapeEventImpl>();
+ xSet->getPropertyValue( gsOnClick ) >>= pEvent->meClickAction;
+
+ switch( pEvent->meClickAction )
+ {
+ case ClickAction_PREVPAGE:
+ case ClickAction_NEXTPAGE:
+ case ClickAction_FIRSTPAGE:
+ case ClickAction_LASTPAGE:
+ case ClickAction_STOPPRESENTATION:
+ break;
+ case ClickAction_BOOKMARK:
+ if( xSetInfo->hasPropertyByName( gsBookmark ) )
+ xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
+ if( getSlideNumberForBookmark( pEvent->maStrBookmark ) == -1 )
+ continue;
+ break;
+ case ClickAction_DOCUMENT:
+ case ClickAction_SOUND:
+ case ClickAction_PROGRAM:
+ case ClickAction_MACRO:
+ if( xSetInfo->hasPropertyByName( gsBookmark ) )
+ xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
+ break;
+ case ClickAction_VERB:
+ if( xSetInfo->hasPropertyByName( gsVerb ) )
+ xSet->getPropertyValue( gsVerb ) >>= pEvent->mnVerb;
+ break;
+ default:
+ continue; // skip all others
+ }
+
+ maShapeEventMap[ xShape ] = pEvent;
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->addShapeEventListener( xShape );
+ mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects)
+{
+ stopSound();
+ removeShapeEvents();
+
+ if( mpSlideController && mxShow.is() )
+ {
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(),
+ UNO_QUERY_THROW );
+ mpSlideController->displayCurrentSlide( mxShow, xDrawPages, bSkipAllMainSequenceEffects );
+ registerShapeEvents(mpSlideController->getCurrentSlideNumber());
+ update();
+
+ }
+ // send out page change event and notify to update all acc info for current page
+ if (mpViewShell)
+ {
+ sal_Int32 currentPageIndex = getCurrentSlideIndex();
+ mpViewShell->fireSwitchCurrentPage(currentPageIndex);
+ mpViewShell->NotifyAccUpdate();
+ }
+}
+
+void SlideshowImpl::endPresentation()
+{
+ if( maPresSettings.mbMouseAsPen)
+ {
+ Reference< XMultiServiceFactory > xDocFactory(mpDoc->getUnoModel(), UNO_QUERY );
+ if( xDocFactory.is() )
+ mxShow->registerUserPaintPolygons(xDocFactory);
+ }
+
+ if( !mnEndShowEvent )
+ mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) );
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, endPresentationHdl, void*, void)
+{
+ mnEndShowEvent = nullptr;
+
+ stopSound();
+
+ if( mxPresentation.is() )
+ mxPresentation->end();
+}
+
+void SAL_CALL SlideshowImpl::pause()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ return;
+
+ try
+ {
+ mbIsPaused = true;
+ if( mxShow.is() )
+ {
+ mxShow->pause(true);
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->paused();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::resume()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused ) try
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK || mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ mbIsPaused = false;
+ if( mxShow.is() )
+ {
+ mxShow->pause(false);
+ update();
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->resumed();
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" );
+ }
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::presentationStarted( this );
+#endif
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isPaused()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbIsPaused;
+}
+
+void SAL_CALL SlideshowImpl::blankScreen( sal_Int32 nColor )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mpShowWindow && mpSlideController )
+ {
+ if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), Color(ColorTransparency, nColor) ) )
+ {
+ pause();
+ }
+ }
+}
+
+// XShapeEventListener
+
+void SlideshowImpl::click( const Reference< XShape >& xShape )
+{
+ SolarMutexGuard aSolarGuard;
+
+ WrappedShapeEventImplPtr pEvent = maShapeEventMap[xShape];
+ if( !pEvent )
+ return;
+
+ switch( pEvent->meClickAction )
+ {
+ case ClickAction_PREVPAGE: gotoPreviousSlide(); break;
+ case ClickAction_NEXTPAGE: gotoNextSlide(); break;
+ case ClickAction_FIRSTPAGE: gotoFirstSlide(); break;
+ case ClickAction_LASTPAGE: gotoLastSlide(); break;
+ case ClickAction_STOPPRESENTATION: endPresentation(); break;
+ case ClickAction_BOOKMARK:
+ {
+ gotoBookmark( pEvent->maStrBookmark );
+ }
+ break;
+ case ClickAction_SOUND:
+ {
+#if HAVE_FEATURE_AVMEDIA
+ try
+ {
+ mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark, ""/*TODO?*/), uno::UNO_SET_THROW );
+ mxPlayer->start();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" );
+ }
+#endif
+ }
+ break;
+
+ case ClickAction_DOCUMENT:
+ {
+ OUString aBookmark( pEvent->maStrBookmark );
+
+ sal_Int32 nPos = aBookmark.indexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL( aBookmark.copy( 0, nPos+1 ) );
+ OUString aName( aBookmark.copy( nPos+1 ) );
+ aURL += getUiNameFromPageApiNameImpl( aName );
+ aBookmark = aURL;
+ }
+
+ mpDocSh->OpenBookmark( aBookmark );
+ }
+ break;
+
+ case ClickAction_PROGRAM:
+ {
+ INetURLObject aURL(
+ ::URIHelper::SmartRel2Abs(
+ INetURLObject(mpDocSh->GetMedium()->GetBaseURL()),
+ pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true,
+ false, INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous ) );
+
+ if( INetProtocol::File == aURL.GetProtocol() )
+ {
+ SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ SfxBoolItem aBrowsing( SID_BROWSE, true );
+
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pViewFrm->GetFrame().GetFrameInterface());
+ pViewFrm->GetDispatcher()->ExecuteList( SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aUrl, &aBrowsing }, { &aDocFrame } );
+ }
+ }
+ }
+ break;
+
+#if HAVE_FEATURE_SCRIPTING
+ case presentation::ClickAction_MACRO:
+ {
+ const OUString aMacro( pEvent->maStrBookmark );
+
+ if ( SfxApplication::IsXScriptURL( aMacro ) )
+ {
+ Any aRet;
+ Sequence< sal_Int16 > aOutArgsIndex;
+ Sequence< Any > aOutArgs;
+ Sequence< Any >* pInArgs = new Sequence< Any >(0);
+ mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
+ }
+ else
+ {
+ // aMacro has the following syntax:
+ // "Macroname.Modulname.Libname.Documentname" or
+ // "Macroname.Modulname.Libname.Applicationname"
+ sal_Int32 nIdx{ 0 };
+ const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
+ const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
+
+ // todo: is the limitation still given that only
+ // Modulname+Macroname can be used here?
+ OUString aExecMacro = OUString::Concat(aModulName) + "." + aMacroName;
+ mpDocSh->GetBasic()->Call(aExecMacro);
+ }
+ }
+ break;
+#endif
+
+ case ClickAction_VERB:
+ {
+ // todo, better do it async?
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ SdrOle2Obj* pOleObject = dynamic_cast< SdrOle2Obj* >(pObj);
+ if (pOleObject && mpViewShell )
+ mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark )
+{
+ bool bIsMasterPage;
+ OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark );
+ sal_uInt16 nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage );
+
+ if( nPgNum == SDRPAGE_NOTFOUND )
+ {
+ // Is the bookmark an object?
+ SdrObject* pObj = mpDoc->GetObj( aBookmark );
+
+ if( pObj )
+ {
+ nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ bIsMasterPage = pObj->getSdrPageFromSdrObject()->IsMasterPage();
+ }
+ }
+
+ if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PageKind::Standard )
+ return -1;
+
+ return ( nPgNum - 1) >> 1;
+}
+
+void SlideshowImpl::contextMenuShow(const css::awt::Point& point)
+{
+ maPopupMousePos = { point.X, point.Y };
+ mnContextMenuEvent = Application::PostUserEvent(LINK(this, SlideshowImpl, ContextMenuHdl));
+}
+
+void SlideshowImpl::hyperLinkClicked( OUString const& aHyperLink )
+{
+ OUString aBookmark( aHyperLink );
+
+ sal_Int32 nPos = aBookmark.indexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL( aBookmark.copy( 0, nPos+1 ) );
+ OUString aName( aBookmark.copy( nPos+1 ) );
+ aURL += getUiNameFromPageApiNameImpl( aName );
+ aBookmark = aURL;
+ }
+
+ mpDocSh->OpenBookmark( aBookmark );
+}
+
+void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber )
+{
+ if( mpSlideController )
+ {
+ if( mpSlideController->jumpToSlideNumber( nSlideNumber ) )
+ {
+ displayCurrentSlide();
+ }
+ }
+}
+
+/** nSlideIndex == -1 displays current slide again */
+void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex )
+{
+ if( mpSlideController )
+ {
+ if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) )
+ {
+ displayCurrentSlide();
+ }
+ }
+}
+
+void SlideshowImpl::jumpToBookmark( const OUString& sBookmark )
+{
+ sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark );
+ if( nSlideNumber != -1 )
+ displaySlideNumber( nSlideNumber );
+}
+
+sal_Int32 SlideshowImpl::getCurrentSlideNumber() const
+{
+ return mpSlideController ? mpSlideController->getCurrentSlideNumber() : -1;
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isEndless()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbEndless;
+}
+
+void SlideshowImpl::update()
+{
+ startUpdateTimer();
+}
+
+void SlideshowImpl::startUpdateTimer()
+{
+ SolarMutexGuard aSolarGuard;
+ maUpdateTimer.SetTimeout( 0 );
+ maUpdateTimer.Start();
+}
+
+/** this timer is called 20ms after a new slide was displayed.
+ This is used to unfreeze user input that was disabled after
+ slide change to skip input that was buffered during slide
+ transition preparation */
+IMPL_LINK_NOARG(SlideshowImpl, ReadyForNextInputHdl, Timer *, void)
+{
+ mbInputFreeze = false;
+}
+
+/** if I catch someone someday who calls this method by hand
+ and not by using the timer, I will personally punish this
+ person seriously, even if this person is me.
+*/
+IMPL_LINK_NOARG(SlideshowImpl, updateHdl, Timer *, void)
+{
+ updateSlideShow();
+}
+
+void SlideshowImpl::updateSlideShow()
+{
+ // prevent me from deletion when recursing (App::EnableYieldMode does)
+ const rtl::Reference<SlideshowImpl> xKeepAlive(this);
+
+ Reference< XSlideShow > xShow( mxShow );
+ if ( ! xShow.is())
+ return;
+
+ try
+ {
+ double fUpdate = 0.0;
+ if( !xShow->update(fUpdate) )
+ fUpdate = -1.0;
+
+ if (mxShow.is() && (fUpdate >= 0.0))
+ {
+ if (::basegfx::fTools::equalZero(fUpdate))
+ {
+ // Make sure idle tasks don't starve when we don't have to wait.
+ // Don't process any events generated after invoking the function.
+ Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
+ }
+ else
+ {
+ // Avoid busy loop when the previous call to update()
+ // returns a small positive number but not 0 (which is
+ // handled above). Also, make sure that calls to update()
+ // have a minimum frequency.
+ // => Allow up to 60 frames per second. Call at least once
+ // every 4 seconds.
+ const static sal_Int32 nMaximumFrameCount (60);
+ const static double nMinimumTimeout (1.0 / nMaximumFrameCount);
+ const static double nMaximumTimeout (4.0);
+ fUpdate = std::clamp(fUpdate, nMinimumTimeout, nMaximumTimeout);
+
+ // Make sure that the maximum frame count has not been set
+ // too high (only then conversion to milliseconds and long
+ // integer may lead to zero value.)
+ OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
+ }
+
+ // Use our high resolution timers for the asynchronous callback.
+ maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
+ maUpdateTimer.Start();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
+ }
+}
+
+bool SlideshowImpl::keyInput(const KeyEvent& rKEvt)
+{
+ if( !mxShow.is() || mbInputFreeze )
+ return false;
+
+ bool bRet = true;
+
+ try
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case awt::Key::CONTEXTMENU:
+ if( !mnContextMenuEvent )
+ {
+ if( mpShowWindow )
+ maPopupMousePos = mpShowWindow->GetPointerState().maPos;
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+ break;
+
+ // cancel show
+ case KEY_ESCAPE:
+ case KEY_SUBTRACT:
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ endPresentation();
+ break;
+
+ // advance show
+ case KEY_PAGEDOWN:
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ gotoNextSlide();
+ break;
+ }
+ [[fallthrough]];
+ case KEY_SPACE:
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ case KEY_XF86FORWARD:
+ gotoNextEffect();
+ break;
+
+ case KEY_RETURN:
+ {
+ if( !maCharBuffer.isEmpty() )
+ {
+ if( mpSlideController )
+ {
+ if( mpSlideController->jumpToSlideNumber( maCharBuffer.toInt32() - 1 ) )
+ displayCurrentSlide();
+ }
+ maCharBuffer.clear();
+ }
+ else
+ {
+ gotoNextEffect();
+ }
+ }
+ break;
+
+ // numeric: add to buffer
+ case KEY_0:
+ case KEY_1:
+ case KEY_2:
+ case KEY_3:
+ case KEY_4:
+ case KEY_5:
+ case KEY_6:
+ case KEY_7:
+ case KEY_8:
+ case KEY_9:
+ maCharBuffer += OUStringChar( rKEvt.GetCharCode() );
+ break;
+
+ case KEY_PAGEUP:
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ gotoPreviousSlide();
+ break;
+ }
+ [[fallthrough]];
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_BACKSPACE:
+ case KEY_XF86BACK:
+ gotoPreviousEffect();
+ break;
+
+ case KEY_P:
+ setUsePen( !mbUsePen );
+ break;
+
+ // tdf#149351 Ctrl+A disables pointer as pen mode
+ case KEY_A:
+ if(rKEvt.GetKeyCode().IsMod1())
+ {
+ setUsePen( false );
+ break;
+ }
+ break;
+
+ case KEY_E:
+ setEraseAllInk( true );
+ updateSlideShow();
+ break;
+
+ case KEY_HOME:
+ gotoFirstSlide();
+ break;
+
+ case KEY_END:
+ gotoLastSlide();
+ break;
+
+ case KEY_B:
+ case KEY_W:
+ case KEY_POINT:
+ case KEY_COMMA:
+ {
+ blankScreen( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? 0x00ffffff : 0x00000000 );
+ }
+ break;
+
+ default:
+ bRet = false;
+ break;
+ }
+ }
+ catch( Exception& )
+ {
+ bRet = false;
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" );
+ }
+
+ return bRet;
+}
+
+IMPL_LINK( SlideshowImpl, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void )
+{
+ if( !mxShow.is() || mbInputFreeze )
+ return;
+
+ if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) )
+ return;
+
+ const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData());
+
+ if( rEvent.GetCommand() != CommandEventId::Media )
+ return;
+
+ CommandMediaData* pMediaData = rEvent.GetMediaData();
+ pMediaData->SetPassThroughToOS(false);
+ switch (pMediaData->GetMediaId())
+ {
+#if defined( MACOSX )
+ case MediaCommand::Menu:
+ if( !mnContextMenuEvent )
+ {
+ if( mpShowWindow )
+ maPopupMousePos = mpShowWindow->GetPointerState().maPos;
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+ break;
+ case MediaCommand::VolumeDown:
+ gotoPreviousSlide();
+ break;
+ case MediaCommand::VolumeUp:
+ gotoNextEffect();
+ break;
+#endif
+ case MediaCommand::NextTrack:
+ gotoNextEffect();
+ break;
+ case MediaCommand::Pause:
+ if( !mbIsPaused )
+ blankScreen(0);
+ break;
+ case MediaCommand::Play:
+ if( mbIsPaused )
+ resume();
+ break;
+
+ case MediaCommand::PlayPause:
+ if( mbIsPaused )
+ resume();
+ else
+ blankScreen(0);
+ break;
+ case MediaCommand::PreviousTrack:
+ gotoPreviousSlide();
+ break;
+ case MediaCommand::NextTrackHold:
+ gotoLastSlide();
+ break;
+
+ case MediaCommand::Rewind:
+ gotoFirstSlide();
+ break;
+ case MediaCommand::Stop:
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ endPresentation();
+ break;
+ default:
+ pMediaData->SetPassThroughToOS(true);
+ break;
+ }
+}
+
+void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt)
+{
+ if( rMEvt.IsRight() && !mnContextMenuEvent )
+ {
+ maPopupMousePos = rMEvt.GetPosPixel();
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, ContextMenuHdl, void*, void)
+{
+ mnContextMenuEvent = nullptr;
+
+ if (mpSlideController == nullptr)
+ return;
+
+ mbWasPaused = mbIsPaused;
+ if( !mbWasPaused )
+ pause();
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/slidecontextmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+ OUString sNextImage(BMP_MENU_NEXT), sPrevImage(BMP_MENU_PREV);
+ xMenu->insert(0, "next", SdResId(RID_SVXSTR_MENU_NEXT), &sNextImage, nullptr, nullptr, TRISTATE_INDET);
+ xMenu->insert(1, "prev", SdResId(RID_SVXSTR_MENU_PREV), &sPrevImage, nullptr, nullptr, TRISTATE_INDET);
+
+ // Adding button to display if in Pen mode
+ xMenu->set_active("pen", mbUsePen);
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ xMenu->set_visible("next", mpSlideController->getNextSlideIndex() != -1);
+ xMenu->set_visible("prev", (mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK));
+ xMenu->set_visible("edit", mpViewShell->GetDoc()->IsStartWithPresentation());
+
+ std::unique_ptr<weld::Menu> xPageMenu(xBuilder->weld_menu("gotomenu"));
+ OUString sFirstImage(BMP_MENU_FIRST), sLastImage(BMP_MENU_LAST);
+ xPageMenu->insert(0, "first", SdResId(RID_SVXSTR_MENU_FIRST), &sFirstImage, nullptr, nullptr, TRISTATE_INDET);
+ xPageMenu->insert(1, "last", SdResId(RID_SVXSTR_MENU_LAST), &sLastImage, nullptr, nullptr, TRISTATE_INDET);
+
+ // populate slide goto list
+ const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount();
+ if( nPageNumberCount <= 1 )
+ {
+ xMenu->set_visible("goto", false);
+ }
+ else
+ {
+ sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber();
+ if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ nCurrentSlideNumber = -1;
+
+ xPageMenu->set_visible("first", mpSlideController->getSlideNumber(0) != nCurrentSlideNumber);
+ xPageMenu->set_visible("last", mpSlideController->getSlideNumber(mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber);
+
+ sal_Int32 nPageNumber;
+
+ for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ )
+ {
+ if( mpSlideController->isVisibleSlideNumber( nPageNumber ) )
+ {
+ SdPage* pPage = mpDoc->GetSdPage(static_cast<sal_uInt16>(nPageNumber), PageKind::Standard);
+ if (pPage)
+ {
+ OUString sId(OUString::number(CM_SLIDES + nPageNumber));
+ xPageMenu->append_check(sId, pPage->GetName());
+ if (nPageNumber == nCurrentSlideNumber)
+ xPageMenu->set_active(sId, true);
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<weld::Menu> xBlankMenu(xBuilder->weld_menu("screenmenu"));
+
+ if (mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK)
+ {
+ xBlankMenu->set_active((mpShowWindow->GetBlankColor() == COL_WHITE) ? "white" : "black", true);
+ }
+
+ std::unique_ptr<weld::Menu> xWidthMenu(xBuilder->weld_menu("widthmenu"));
+
+ // populate color width list
+ sal_Int32 nIterator;
+ double nWidth;
+
+ nWidth = 4.0;
+ for( nIterator = 1; nIterator < 6; nIterator++)
+ {
+ switch(nIterator)
+ {
+ case 1:
+ nWidth = 4.0;
+ break;
+ case 2:
+ nWidth = 100.0;
+ break;
+ case 3:
+ nWidth = 150.0;
+ break;
+ case 4:
+ nWidth = 200.0;
+ break;
+ case 5:
+ nWidth = 400.0;
+ break;
+ default:
+ break;
+ }
+
+ if (nWidth == mdUserPaintStrokeWidth)
+ xWidthMenu->set_active(OUString::number(nWidth), true);
+ }
+
+ ::tools::Rectangle aRect(maPopupMousePos, Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*mpShowWindow, aRect);
+ ContextMenuSelectHdl(xMenu->popup_at_rect(pParent, aRect));
+
+ if( mxView.is() )
+ mxView->ignoreNextMouseReleased();
+
+ if( !mbWasPaused )
+ resume();
+}
+
+void SlideshowImpl::ContextMenuSelectHdl(std::u16string_view rMenuId)
+{
+ if (rMenuId == u"prev")
+ {
+ gotoPreviousSlide();
+ mbWasPaused = false;
+ }
+ else if(rMenuId == u"next")
+ {
+ gotoNextSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"first")
+ {
+ gotoFirstSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"last")
+ {
+ gotoLastSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"black" || rMenuId == u"white")
+ {
+ const Color aBlankColor(rMenuId == u"white" ? COL_WHITE : COL_BLACK);
+ if( mbWasPaused )
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
+ {
+ if( mpShowWindow->GetBlankColor() == aBlankColor )
+ {
+ mbWasPaused = false;
+ mpShowWindow->RestartShow();
+ return;
+ }
+ }
+ mpShowWindow->RestartShow();
+ }
+ if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
+ {
+ pause();
+ mbWasPaused = true;
+ }
+ }
+ else if (rMenuId == u"color")
+ {
+ //Open a color picker based on SvColorDialog
+ ::Color aColor( ColorTransparency, mnUserPaintColor );
+ SvColorDialog aColorDlg;
+ aColorDlg.SetColor( aColor );
+
+ if (aColorDlg.Execute(mpShowWindow->GetFrameWeld()))
+ {
+ aColor = aColorDlg.GetColor();
+ setPenColor(sal_Int32(aColor));
+ }
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"4")
+ {
+ setPenWidth(4.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"100")
+ {
+ setPenWidth(100.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"150")
+ {
+ setPenWidth(150.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"200")
+ {
+ setPenWidth(200.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"400")
+ {
+ setPenWidth(400.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"erase")
+ {
+ setEraseAllInk(true);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"pen")
+ {
+ setUsePen(!mbUsePen);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == u"edit")
+ {
+ // When in autoplay mode (pps/ppsx), offer editing of the presentation
+ // Turn autostart off, else Impress will close when exiting the Presentation
+ mpViewShell->GetDoc()->SetExitAfterPresenting(false);
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ {
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ }
+ endPresentation();
+ }
+ else if (rMenuId == u"end")
+ {
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ {
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ }
+ endPresentation();
+ }
+ else if (!rMenuId.empty())
+ {
+ sal_Int32 nPageNumber = o3tl::toInt32(rMenuId) - CM_SLIDES;
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow( nPageNumber );
+ }
+ else if( nPageNumber != mpSlideController->getCurrentSlideNumber() )
+ {
+ displaySlideNumber( nPageNumber );
+ }
+ mbWasPaused = false;
+ }
+}
+
+Reference< XSlideShow > SlideshowImpl::createSlideShow()
+{
+ Reference< XSlideShow > xShow;
+
+ try
+ {
+ Reference< uno::XComponentContext > xContext =
+ ::comphelper::getProcessComponentContext();
+
+ xShow.set( presentation::SlideShow::create(xContext), UNO_SET_THROW );
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" );
+ }
+
+ return xShow;
+}
+
+void SlideshowImpl::createSlideList( bool bAll, std::u16string_view rPresSlide )
+{
+ const sal_uInt16 nSlideCount = mpDoc->GetSdPageCount( PageKind::Standard );
+
+ if( !nSlideCount )
+ return;
+
+ SdCustomShow* pCustomShow;
+
+ if( mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow )
+ pCustomShow = mpDoc->GetCustomShowList()->GetCurObject();
+ else
+ pCustomShow = nullptr;
+
+ // create animation slide controller
+ AnimationSlideController::Mode eMode =
+ ( pCustomShow && !pCustomShow->PagesVector().empty() ) ? AnimationSlideController::CUSTOM :
+ (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM);
+
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+ mpSlideController = std::make_shared<AnimationSlideController>( xSlides, eMode );
+
+ if( eMode != AnimationSlideController::CUSTOM )
+ {
+ sal_Int32 nFirstVisibleSlide = 0;
+
+ // normal presentation
+ if( !rPresSlide.empty() )
+ {
+ sal_Int32 nSlide;
+ bool bTakeNextAvailable = false;
+
+ for( nSlide = 0, nFirstVisibleSlide = -1;
+ ( nSlide < nSlideCount ) && ( -1 == nFirstVisibleSlide ); nSlide++ )
+ {
+ SdPage* pTestSlide = mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard );
+
+ if( pTestSlide->GetName() == rPresSlide )
+ {
+ if( pTestSlide->IsExcluded() )
+ bTakeNextAvailable = true;
+ else
+ nFirstVisibleSlide = nSlide;
+ }
+ else if( bTakeNextAvailable && !pTestSlide->IsExcluded() )
+ nFirstVisibleSlide = nSlide;
+ }
+
+ if( -1 == nFirstVisibleSlide )
+ nFirstVisibleSlide = 0;
+ }
+
+ for( sal_Int32 i = 0; i < nSlideCount; i++ )
+ {
+ bool bVisible = ! mpDoc->GetSdPage( static_cast<sal_uInt16>(i), PageKind::Standard )->IsExcluded();
+ if( bVisible || (eMode == AnimationSlideController::ALL) )
+ mpSlideController->insertSlideNumber( i, bVisible );
+ }
+
+ mpSlideController->setStartSlideNumber( nFirstVisibleSlide );
+ }
+ else
+ {
+ if( meAnimationMode != ANIMATIONMODE_SHOW && !rPresSlide.empty() )
+ {
+ sal_Int32 nSlide;
+ for( nSlide = 0; nSlide < nSlideCount; nSlide++ )
+ if( rPresSlide == mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard )->GetName() )
+ break;
+
+ if( nSlide < nSlideCount )
+ mpSlideController->insertSlideNumber( static_cast<sal_uInt16>(nSlide) );
+ }
+
+ for( const auto& rpPage : pCustomShow->PagesVector() )
+ {
+ const sal_uInt16 nSdSlide = ( rpPage->GetPageNum() - 1 ) / 2;
+
+ if( ! mpDoc->GetSdPage( nSdSlide, PageKind::Standard )->IsExcluded())
+ mpSlideController->insertSlideNumber( nSdSlide );
+ }
+ }
+}
+
+typedef sal_uInt16 (*FncGetChildWindowId)();
+
+const FncGetChildWindowId aShowChildren[] =
+{
+ &AnimationChildWindow::GetChildWindowId,
+ &Svx3DChildWindow::GetChildWindowId,
+ &SvxFontWorkChildWindow::GetChildWindowId,
+ &SvxColorChildWindow::GetChildWindowId,
+ &SvxSearchDialogWrapper::GetChildWindowId,
+ &SvxBmpMaskChildWindow::GetChildWindowId,
+ &SvxIMapDlgChildWindow::GetChildWindowId,
+ &SvxHlinkDlgWrapper::GetChildWindowId,
+ &SfxInfoBarContainerChild::GetChildWindowId
+};
+
+void SlideshowImpl::hideChildWindows()
+{
+ mnChildMask = 0;
+
+ if( ANIMATIONMODE_SHOW != meAnimationMode )
+ return;
+
+ SfxViewFrame* pViewFrame = getViewFrame();
+
+ if( !pViewFrame )
+ return;
+
+ for( sal_uLong i = 0; i < SAL_N_ELEMENTS( aShowChildren ); i++ )
+ {
+ const sal_uInt16 nId = ( *aShowChildren[ i ] )();
+
+ if( pViewFrame->GetChildWindow( nId ) )
+ {
+ pViewFrame->SetChildWindow( nId, false );
+ mnChildMask |= ::tools::ULong(1) << i;
+ }
+ }
+}
+
+void SlideshowImpl::showChildWindows()
+{
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ SfxViewFrame* pViewFrame = getViewFrame();
+ if( pViewFrame )
+ {
+ for( sal_uLong i = 0; i < SAL_N_ELEMENTS(aShowChildren); i++ )
+ {
+ if( mnChildMask & ( ::tools::ULong(1) << i ) )
+ pViewFrame->SetChildWindow( ( *aShowChildren[ i ] )(), true );
+ }
+ }
+ }
+}
+
+SfxViewFrame* SlideshowImpl::getViewFrame() const
+{
+ return mpViewShell ? mpViewShell->GetViewFrame() : nullptr;
+}
+
+SfxDispatcher* SlideshowImpl::getDispatcher() const
+{
+ return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : nullptr;
+}
+
+SfxBindings* SlideshowImpl::getBindings() const
+{
+ return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : nullptr;
+}
+
+void SlideshowImpl::resize( const Size& rSize )
+{
+ maPresSize = rSize;
+
+ if(mpShowWindow)
+ {
+ mpShowWindow->SetSizePixel( maPresSize );
+ mpShowWindow->Show();
+ }
+
+ if( mxView.is() ) try
+ {
+ awt::WindowEvent aEvt;
+ mxView->windowResized(aEvt);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" );
+ }
+}
+
+void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible )
+{
+ // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode
+ // actually it runs always in window mode in case of ActiveX control
+ if ( !(!maPresSettings.mbFullScreen && mpDocSh && mpDocSh->GetMedium()) )
+ return;
+
+ const SfxBoolItem* pItem = mpDocSh->GetMedium()->GetItemSet().GetItem(SID_VIEWONLY, false);
+ if ( !(pItem && pItem->GetValue()) )
+ return;
+
+ // this is a plugin/activex mode, no toolbars should be visible during slide show
+ // after the end of slide show they should be visible again
+ SfxViewFrame* pViewFrame = getViewFrame();
+ if( !pViewFrame )
+ return;
+
+ try
+ {
+ Reference< frame::XLayoutManager > xLayoutManager;
+ Reference< beans::XPropertySet > xFrameProps( pViewFrame->GetFrame().GetFrameInterface(), UNO_QUERY_THROW );
+ if ( ( xFrameProps->getPropertyValue( "LayoutManager" )
+ >>= xLayoutManager )
+ && xLayoutManager.is() )
+ {
+ xLayoutManager->setVisible( bVisible );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+}
+
+void SAL_CALL SlideshowImpl::activate()
+{
+ SolarMutexGuard aSolarGuard;
+
+ maDeactivateTimer.Stop();
+
+ if( mbActive || !mxShow.is() )
+ return;
+
+ mbActive = true;
+
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( false );
+
+ if( mpShowWindow )
+ {
+ SfxViewFrame* pViewFrame = getViewFrame();
+ SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : nullptr;
+
+ hideChildWindows();
+
+ if( pDispatcher )
+ {
+ // filter all forbidden slots
+ pDispatcher->SetSlotFilter( SfxSlotFilterState::ENABLED, pAllowed );
+ }
+
+ if( getBindings() )
+ getBindings()->InvalidateAll(true);
+
+ mpShowWindow->GrabFocus();
+ }
+ }
+
+ resume();
+}
+
+void SAL_CALL SlideshowImpl::deactivate()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbActive && mxShow.is() )
+ {
+ maDeactivateTimer.Start();
+ }
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, deactivateHdl, Timer *, void)
+{
+ if( !(mbActive && mxShow.is()) )
+ return;
+
+ mbActive = false;
+
+ pause();
+
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( true );
+
+ if( mpShowWindow )
+ {
+ showChildWindows();
+ }
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isActive()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbActive;
+}
+
+void SlideshowImpl::setAutoSaveState( bool bOn)
+{
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ uno::Reference< util::XURLTransformer > xParser(util::URLTransformer::create(xContext));
+ util::URL aURL;
+ aURL.Complete = "vnd.sun.star.autorecovery:/setAutoSaveState";
+ xParser->parseStrict(aURL);
+
+ Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("AutoSaveState", bOn) };
+
+ uno::Reference< frame::XDispatch > xAutoSave = frame::theAutoRecovery::get(xContext);
+ xAutoSave->dispatch(aURL, aArgs);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()");
+ }
+}
+
+Reference< XDrawPage > SAL_CALL SlideshowImpl::getCurrentSlide()
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XDrawPage > xSlide;
+ if( mxShow.is() && mpSlideController )
+ {
+ sal_Int32 nSlide = getCurrentSlideNumber();
+ if( (nSlide >= 0) && (nSlide < mpSlideController->getSlideNumberCount() ) )
+ xSlide = mpSlideController->getSlideByNumber( nSlide );
+ }
+
+ return xSlide;
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getNextSlideIndex()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mxShow.is() )
+ {
+ return mpSlideController->getNextSlideIndex();
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getCurrentSlideIndex()
+{
+ return mpSlideController ? mpSlideController->getCurrentSlideIndex() : -1;
+}
+
+// css::presentation::XSlideShowController:
+
+::sal_Int32 SAL_CALL SlideshowImpl::getSlideCount()
+{
+ return mpSlideController ? mpSlideController->getSlideIndexCount() : 0;
+}
+
+Reference< XDrawPage > SAL_CALL SlideshowImpl::getSlideByIndex(::sal_Int32 Index)
+{
+ if ((mpSlideController == nullptr) || (Index < 0)
+ || (Index >= mpSlideController->getSlideIndexCount()))
+ throw IndexOutOfBoundsException();
+
+ return mpSlideController->getSlideByNumber( mpSlideController->getSlideNumber( Index ) );
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getAlwaysOnTop()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbAlwaysOnTop;
+}
+
+void SAL_CALL SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways )
+{
+ SolarMutexGuard aSolarGuard;
+ if( maPresSettings.mbAlwaysOnTop != bool(bAlways) )
+ {
+ maPresSettings.mbAlwaysOnTop = bAlways;
+ // todo, can this be changed while running?
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isFullScreen()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbFullScreen;
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getMouseVisible()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbMouseVisible;
+}
+
+void SAL_CALL SlideshowImpl::setMouseVisible( sal_Bool bVisible )
+{
+ SolarMutexGuard aSolarGuard;
+ if( maPresSettings.mbMouseVisible != bool(bVisible) )
+ {
+ maPresSettings.mbMouseVisible = bVisible;
+ if( mpShowWindow )
+ mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getUsePen()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbUsePen;
+}
+
+void SAL_CALL SlideshowImpl::setUsePen( sal_Bool bMouseAsPen )
+{
+ SolarMutexGuard aSolarGuard;
+ mbUsePen = bMouseAsPen;
+ if( !mxShow.is() )
+ return;
+
+ try
+ {
+ // For Pencolor;
+ Any aValue;
+ if( mbUsePen )
+ aValue <<= mnUserPaintColor;
+ beans::PropertyValue aPenProp;
+ aPenProp.Name = "UserPaintColor";
+ aPenProp.Value = aValue;
+ mxShow->setProperty( aPenProp );
+
+ //for StrokeWidth :
+ if( mbUsePen )
+ {
+ beans::PropertyValue aPenPropWidth;
+ aPenPropWidth.Name = "UserPaintStrokeWidth";
+ aPenPropWidth.Value <<= mdUserPaintStrokeWidth;
+ mxShow->setProperty( aPenPropWidth );
+
+ // for Pen Mode
+ beans::PropertyValue aPenPropSwitchPenMode;
+ aPenPropSwitchPenMode.Name = "SwitchPenMode";
+ aPenPropSwitchPenMode.Value <<= true;
+ mxShow->setProperty( aPenPropSwitchPenMode );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" );
+ }
+}
+
+double SAL_CALL SlideshowImpl::getPenWidth()
+{
+ SolarMutexGuard aSolarGuard;
+ return mdUserPaintStrokeWidth;
+}
+
+void SAL_CALL SlideshowImpl::setPenWidth( double dStrokeWidth )
+{
+ SolarMutexGuard aSolarGuard;
+ mdUserPaintStrokeWidth = dStrokeWidth;
+ setUsePen( true ); // enable pen mode, update color and width
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getPenColor()
+{
+ SolarMutexGuard aSolarGuard;
+ return mnUserPaintColor;
+}
+
+void SAL_CALL SlideshowImpl::setPenColor( sal_Int32 nColor )
+{
+ SolarMutexGuard aSolarGuard;
+ mnUserPaintColor = nColor;
+ setUsePen( true ); // enable pen mode, update color
+}
+
+void SAL_CALL SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk)
+{
+ if( !bEraseAllInk )
+ return;
+
+ SolarMutexGuard aSolarGuard;
+ if( !mxShow.is() )
+ return;
+
+ try
+ {
+ beans::PropertyValue aPenPropEraseAllInk;
+ aPenPropEraseAllInk.Name = "EraseAllInk";
+ aPenPropEraseAllInk.Value <<= bEraseAllInk;
+ mxShow->setProperty( aPenPropEraseAllInk );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" );
+ }
+}
+
+// XSlideShowController Methods
+sal_Bool SAL_CALL SlideshowImpl::isRunning( )
+{
+ SolarMutexGuard aSolarGuard;
+ return mxShow.is();
+}
+
+void SAL_CALL SlideshowImpl::gotoNextEffect( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController && mpShowWindow) )
+ return;
+
+ if( mbIsPaused && mpShowWindow->GetShowWindowMode() != SHOWWINDOWMODE_END )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( eMode == SHOWWINDOWMODE_END )
+ {
+ endPresentation();
+ }
+ else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ mxShow->nextEffect();
+ update();
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoPreviousEffect( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController && mpShowWindow) )
+ return;
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) || mbIsPaused )
+ {
+ resume();
+ }
+ else
+ {
+ mxShow->previousEffect();
+ update();
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoFirstSlide( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mpShowWindow && mpSlideController) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ if( mpSlideController->getSlideIndexCount() )
+ mpShowWindow->RestartShow( 0);
+ }
+ else
+ {
+ displaySlideIndex( 0 );
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoNextSlide( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ // if this is a show, ignore user inputs and
+ // start 20ms timer to reenable inputs to filter
+ // buffered inputs during slide transition
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mbInputFreeze = true;
+ maInputFreezeTimer.Start();
+ }
+
+ if( mpSlideController )
+ {
+ if( mpSlideController->nextSlide() )
+ {
+ displayCurrentSlide();
+ }
+ else
+ {
+ stopSound();
+
+ if( meAnimationMode == ANIMATIONMODE_PREVIEW )
+ {
+ endPresentation();
+ }
+ else if( maPresSettings.mbEndless )
+ {
+ if( maPresSettings.mnPauseTimeout )
+ {
+ if( mpShowWindow )
+ {
+ if ( maPresSettings.mbShowPauseLogo )
+ {
+ Graphic aGraphic(SfxApplication::GetApplicationLogo(360));
+ mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout, &aGraphic );
+ }
+ else
+ mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout );
+ }
+ }
+ else
+ {
+ displaySlideIndex( 0 );
+ }
+ }
+ else
+ {
+ if( mpShowWindow )
+ {
+ mpShowWindow->SetEndMode();
+ if( !mpViewShell->GetDoc()->IsStartWithPresentation() )
+ pause();
+ }
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoPreviousSlide( )
+{
+ gotoPreviousSlide(false);
+}
+
+void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects)
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController) )
+ return;
+
+ try
+ {
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( eMode == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow( mpSlideController->getCurrentSlideIndex() );
+ }
+ else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ if( mpSlideController->previousSlide())
+ displayCurrentSlide(bSkipAllMainSequenceEffects);
+ else if (bSkipAllMainSequenceEffects)
+ {
+ // We could not go to the previous slide (probably because
+ // the current slide is already the first one). We still
+ // have to call displayCurrentSlide because the calling
+ // slideshow can not determine whether there is a previous
+ // slide or not and has already prepared for a slide change.
+ // This slide change has to be completed now, even when
+ // changing to the same slide.
+ // Note that in this special case we do NOT pass
+ // bSkipAllMainSequenceEffects because we display the same
+ // slide as before and do not want to show all its effects.
+ displayCurrentSlide();
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoLastSlide()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !mpSlideController )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
+ if( nLastSlideIndex >= 0 )
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow( nLastSlideIndex );
+ }
+ else
+ {
+ displaySlideIndex( nLastSlideIndex );
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoBookmark( const OUString& rBookmark )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ sal_Int32 nSlideNumber = getSlideNumberForBookmark( rBookmark );
+ if( nSlideNumber != -1 )
+ displaySlideNumber( nSlideNumber );
+}
+
+void SAL_CALL SlideshowImpl::gotoSlide( const Reference< XDrawPage >& xSlide )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mpSlideController && xSlide.is()) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const sal_Int32 nSlideCount = mpSlideController->getSlideNumberCount();
+ for( sal_Int32 nSlide = 0; nSlide < nSlideCount; nSlide++ )
+ {
+ if( mpSlideController->getSlideByNumber( nSlide ) == xSlide )
+ {
+ displaySlideNumber( nSlide );
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ displaySlideIndex( nIndex );
+}
+
+void SAL_CALL SlideshowImpl::stopSound( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ try
+ {
+ if( mxPlayer.is() )
+ {
+ mxPlayer->stop();
+ mxPlayer.clear();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" );
+ }
+}
+
+// XIndexAccess
+
+::sal_Int32 SAL_CALL SlideshowImpl::getCount( )
+{
+ return getSlideCount();
+}
+
+css::uno::Any SAL_CALL SlideshowImpl::getByIndex( ::sal_Int32 Index )
+{
+ return Any( getSlideByIndex( Index ) );
+}
+
+css::uno::Type SAL_CALL SlideshowImpl::getElementType( )
+{
+ return cppu::UnoType<XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SlideshowImpl::hasElements( )
+{
+ return getSlideCount() != 0;
+}
+
+namespace
+{
+ class AsyncUpdateSlideshow_Impl
+ {
+ public:
+ struct AsyncUpdateSlideshowData
+ {
+ SlideshowImpl* pSlideshowImpl;
+ uno::Reference< css::drawing::XDrawPage > XCurrentSlide;
+ SdrHintKind eHintKind;
+ };
+
+ static ImplSVEvent* AsyncUpdateSlideshow(
+ SlideshowImpl* pSlideshowImpl,
+ uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide,
+ SdrHintKind eHintKind)
+ {
+ AsyncUpdateSlideshowData* pNew(new AsyncUpdateSlideshowData);
+ pNew->pSlideshowImpl = pSlideshowImpl;
+ pNew->XCurrentSlide = rXCurrentSlide;
+ pNew->eHintKind = eHintKind;
+ return Application::PostUserEvent(LINK(nullptr, AsyncUpdateSlideshow_Impl, Update), pNew);
+ // coverity[leaked_storage] - pDisruptor takes care of its own destruction at idle time
+ }
+
+ DECL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, void);
+ };
+
+ IMPL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, pData, void)
+ {
+ AsyncUpdateSlideshowData* pSlideData(static_cast<AsyncUpdateSlideshowData*>(pData));
+ pSlideData->pSlideshowImpl->AsyncNotifyEvent(pSlideData->XCurrentSlide, pSlideData->eHintKind);
+ delete pSlideData;
+ }
+}
+
+void SlideshowImpl::AsyncNotifyEvent(
+ const uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide,
+ const SdrHintKind eHintKind)
+{
+ if (SdrHintKind::ObjectChange == eHintKind)
+ {
+ mnEventObjectChange = nullptr;
+
+ // refresh single slide
+ gotoSlide(rXCurrentSlide);
+ }
+ else if (SdrHintKind::PageOrderChange == eHintKind)
+ {
+ mnEventPageOrderChange = nullptr;
+
+ // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
+ // rXCurrentSlide is the current slide before the change.
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+ const sal_Int32 nNewSlideCount(xSlides.is() ? xSlides->getCount() : 0);
+
+ if (nNewSlideCount != mpSlideController->getSlideNumberCount())
+ {
+ // need to reinitialize AnimationSlideController
+ OUString aPresSlide( maPresSettings.maPresPage );
+ createSlideList( maPresSettings.mbAll, aPresSlide );
+ }
+
+ // Check if current slide before change is still valid (maybe removed)
+ const sal_Int32 nSlideCount(mpSlideController->getSlideNumberCount());
+ bool bSlideStillValid(false);
+
+ for (sal_Int32 nSlide(0); !bSlideStillValid && nSlide < nSlideCount; nSlide++)
+ {
+ if (rXCurrentSlide == mpSlideController->getSlideByNumber(nSlide))
+ {
+ bSlideStillValid = true;
+ }
+ }
+
+ if(bSlideStillValid)
+ {
+ // stay on that slide
+ gotoSlide(rXCurrentSlide);
+ }
+ else
+ {
+ // not possible to stay on that slide, go to 1st slide (kinda restart)
+ gotoFirstSlide();
+ }
+ }
+}
+
+void SlideshowImpl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if (SfxHintId::ThisIsAnSdrHint != rHint.GetId())
+ // nothing to do for non-SdrHints
+ return;
+
+ if (nullptr == mpDoc)
+ // better do nothing when no DrawModel (should not happen)
+ return;
+
+ // tdf#158664 I am surprised, but the 'this' instance keeps incarnated
+ // when the slideshow was running once, so need to check for
+ // SlideShow instance/running to be safe.
+ // NOTE: isRunning() checks mxShow.is(), that is what we want
+ if (!isRunning())
+ // no SlideShow instance or not running, nothing to do
+ return;
+
+ const SdrHintKind eHintKind(static_cast<const SdrHint&>(rHint).GetKind());
+
+ if (SdrHintKind::ObjectChange == eHintKind)
+ {
+ if (nullptr != mnEventObjectChange)
+ // avoid multiple events
+ return;
+
+ // Object changed, object & involved page included in rHint.
+ uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
+ if (!XCurrentSlide.is())
+ return;
+
+ SdrPage* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide));
+ if (nullptr == pCurrentSlide)
+ return;
+
+ const SdrPage* pHintPage(static_cast<const SdrHint&>(rHint).GetPage());
+ if (nullptr == pHintPage)
+ return;
+
+ bool bCurrentSlideIsInvolved(false);
+
+ if (pHintPage->IsMasterPage())
+ {
+ if (pCurrentSlide->TRG_HasMasterPage())
+ {
+ // current slide uses MasterPage on which the change happened
+ bCurrentSlideIsInvolved = (pHintPage == &pCurrentSlide->TRG_GetMasterPage());
+ }
+ }
+ else
+ {
+ // object on current slide was changed
+ bCurrentSlideIsInvolved = (pHintPage == pCurrentSlide);
+ }
+
+ if (!bCurrentSlideIsInvolved)
+ // nothing to do when current slide is not involved
+ return;
+
+ // Refresh current slide. Need to do that asynchronous, else e.g.
+ // text edit changes EditEngine/Outliner are not progressed far
+ // enough (ObjectChanged broadcast which we are in here seems
+ // to early for some cases)
+ mnEventObjectChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
+ }
+ else if (SdrHintKind::PageOrderChange == eHintKind)
+ {
+ // Unfortunately we get multiple events, e.g. when drag/drop position change in
+ // slide sorter on left side of EditView. This includes some with page number +1,
+ // then again -1 (it's a position change). Problem is that in-between already
+ // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1
+ // already. Since we get even more, at least try to take the last one. I found no
+ // good solution yet for this.
+ if (nullptr != mnEventPageOrderChange)
+ Application::RemoveUserEvent( mnEventPageOrderChange );
+
+ // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
+ uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
+ mnEventPageOrderChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
+ }
+ else if (SdrHintKind::ModelCleared == eHintKind)
+ {
+ // immediately end presentation
+ endPresentation();
+ }
+
+ // maybe need to add reactions here to other Hint-Types
+}
+
+Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow()
+{
+ return mxShow;
+}
+
+PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r )
+: PresentationSettings( r )
+, mbRehearseTimings(r.mbRehearseTimings)
+, mbPreview(r.mbPreview)
+, mpParentWindow( nullptr )
+{
+}
+
+PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r )
+: PresentationSettings( r )
+, mbRehearseTimings(false)
+, mbPreview(false)
+, mpParentWindow(nullptr)
+{
+}
+
+void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments )
+{
+ for( const PropertyValue& rValue : rArguments )
+ {
+ SetPropertyValue( rValue.Name, rValue.Value );
+ }
+}
+
+void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, const Any& rValue )
+{
+ if ( rProperty == u"RehearseTimings" )
+ {
+ if( rValue >>= mbRehearseTimings )
+ return;
+ }
+ else if ( rProperty == u"Preview" )
+ {
+ if( rValue >>= mbPreview )
+ return;
+ }
+ else if ( rProperty == u"AnimationNode" )
+ {
+ if( rValue >>= mxAnimationNode )
+ return;
+ }
+ else if ( rProperty == u"ParentWindow" )
+ {
+ Reference< XWindow > xWindow;
+ if( rValue >>= xWindow )
+ {
+ mpParentWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow )
+ : nullptr;
+ return;
+ }
+ }
+ else if ( rProperty == u"AllowAnimations" )
+ {
+ if( rValue >>= mbAnimationAllowed )
+ return;
+ }
+ else if ( rProperty == u"FirstPage" )
+ {
+ OUString aPresPage;
+ if( rValue >>= aPresPage )
+ {
+ maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
+ mbCustomShow = false;
+ mbAll = false;
+ return;
+ }
+ else
+ {
+ if( rValue >>= mxStartPage )
+ return;
+ }
+ }
+ else if ( rProperty == u"IsAlwaysOnTop" )
+ {
+ if( rValue >>= mbAlwaysOnTop )
+ return;
+ }
+ else if ( rProperty == u"IsAutomatic" )
+ {
+ if( rValue >>= mbManual )
+ return;
+ }
+ else if ( rProperty == u"IsEndless" )
+ {
+ if( rValue >>= mbEndless )
+ return;
+ }
+ else if ( rProperty == u"IsFullScreen" )
+ {
+ if( rValue >>= mbFullScreen )
+ return;
+ }
+ else if ( rProperty == u"IsMouseVisible" )
+ {
+ if( rValue >>= mbMouseVisible )
+ return;
+ }
+ else if ( rProperty == u"Pause" )
+ {
+ sal_Int32 nPause = -1;
+ if( (rValue >>= nPause) && (nPause >= 0) )
+ {
+ mnPauseTimeout = nPause;
+ return;
+ }
+ }
+ else if ( rProperty == u"UsePen" )
+ {
+ if( rValue >>= mbMouseAsPen )
+ return;
+ }
+ throw IllegalArgumentException();
+}
+
+// XAnimationListener
+
+SlideShowListenerProxy::SlideShowListenerProxy( rtl::Reference< SlideshowImpl > xController, css::uno::Reference< css::presentation::XSlideShow > xSlideShow )
+: mxController(std::move( xController ))
+, mxSlideShow(std::move( xSlideShow ))
+{
+}
+
+SlideShowListenerProxy::~SlideShowListenerProxy()
+{
+}
+
+void SlideShowListenerProxy::addAsSlideShowListener()
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XSlideShowListener > xSlideShowListener( this );
+ mxSlideShow->addSlideShowListener( xSlideShowListener );
+ }
+}
+
+void SlideShowListenerProxy::removeAsSlideShowListener()
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XSlideShowListener > xSlideShowListener( this );
+ mxSlideShow->removeSlideShowListener( xSlideShowListener );
+ }
+}
+
+void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XShapeEventListener > xListener( this );
+ mxSlideShow->addShapeEventListener( xListener, xShape );
+ }
+}
+
+void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XShapeEventListener > xListener( this );
+ mxSlideShow->removeShapeEventListener( xListener, xShape );
+ }
+}
+
+void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
+{
+ std::unique_lock g(m_aMutex);
+ maListeners.addInterface(g, xListener);
+}
+
+void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
+{
+ std::unique_lock g(m_aMutex);
+ maListeners.removeInterface(g, xListener);
+}
+
+void SAL_CALL SlideShowListenerProxy::beginEvent( const Reference< XAnimationNode >& xNode )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maListeners.getLength(aGuard) >= 0 )
+ {
+ maListeners.forEach(aGuard,
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->beginEvent(xNode);
+ } );
+ }
+}
+
+void SAL_CALL SlideShowListenerProxy::endEvent( const Reference< XAnimationNode >& xNode )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maListeners.getLength(aGuard) >= 0 )
+ {
+ maListeners.forEach(aGuard,
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->endEvent(xNode);
+ } );
+ }
+}
+
+void SAL_CALL SlideShowListenerProxy::repeat( const Reference< XAnimationNode >& xNode, ::sal_Int32 nRepeat )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maListeners.getLength(aGuard) >= 0 )
+ {
+ maListeners.forEach(aGuard,
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->repeat(xNode, nRepeat);
+ } );
+ }
+}
+
+// css::presentation::XSlideShowListener:
+
+void SAL_CALL SlideShowListenerProxy::paused( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ maListeners.forEach(aGuard,
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->paused();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::resumed( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ maListeners.forEach(aGuard,
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->resumed();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideTransitionStarted( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ maListeners.forEach(aGuard,
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideTransitionStarted();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideTransitionEnded( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ maListeners.forEach(aGuard,
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideTransitionEnded ();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideAnimationsEnded( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ maListeners.forEach(aGuard,
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideAnimationsEnded ();
+ });
+}
+
+void SlideShowListenerProxy::slideEnded(sal_Bool bReverse)
+{
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maListeners.getLength(aGuard) >= 0 )
+ {
+ maListeners.forEach(aGuard,
+ [&] (Reference<XSlideShowListener> const& xListener) {
+ return xListener->slideEnded(bReverse);
+ } );
+ }
+ }
+
+ {
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->slideEnded(bReverse);
+ }
+}
+
+void SlideShowListenerProxy::hyperLinkClicked( OUString const& aHyperLink )
+{
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maListeners.getLength(aGuard) >= 0 )
+ {
+ maListeners.forEach(aGuard,
+ [&] (Reference<XSlideShowListener> const& xListener) {
+ return xListener->hyperLinkClicked(aHyperLink);
+ } );
+ }
+ }
+
+ {
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->hyperLinkClicked(aHyperLink);
+ }
+}
+
+// XEventListener
+
+void SAL_CALL SlideShowListenerProxy::disposing( const css::lang::EventObject& aDisposeEvent )
+{
+ std::unique_lock g(m_aMutex);
+ maListeners.disposeAndClear( g, aDisposeEvent );
+ mxController.clear();
+ mxSlideShow.clear();
+}
+
+// XShapeEventListener
+
+void SAL_CALL SlideShowListenerProxy::click( const Reference< XShape >& xShape, const css::awt::MouseEvent& /*aOriginalEvent*/ )
+{
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->click(xShape );
+}
+
+void SAL_CALL SlideShowListenerProxy::contextMenuShow(const css::awt::Point& point)
+{
+ SolarMutexGuard aSolarGuard;
+ if (mxController.is())
+ mxController->contextMenuShow(point);
+}
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowimpl.hxx b/sd/source/ui/slideshow/slideshowimpl.hxx
new file mode 100644
index 0000000000..155cdc329f
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowimpl.hxx
@@ -0,0 +1,355 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <com/sun/star/presentation/XSlideShowNavigationListener.hpp>
+#include <com/sun/star/presentation/XSlideShowController.hpp>
+#include <com/sun/star/presentation/XShapeEventListener.hpp>
+
+#include <drawdoc.hxx>
+
+#include "showwindow.hxx"
+
+#include <slideshow.hxx>
+
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::media { class XPlayer; }
+namespace sd { class DrawDocShell; }
+namespace sd { class ViewShell; }
+
+class SfxBindings;
+class SfxDispatcher;
+class SfxViewFrame;
+class StarBASIC;
+
+namespace sd
+{
+class SlideShowView;
+class AnimationSlideController;
+class PaneHider;
+
+struct PresentationSettingsEx : public PresentationSettings
+{
+ bool mbRehearseTimings;
+ bool mbPreview;
+ VclPtr<vcl::Window> mpParentWindow;
+ css::uno::Reference< css::drawing::XDrawPage > mxStartPage;
+ css::uno::Reference< css::animations::XAnimationNode > mxAnimationNode;
+
+ PresentationSettingsEx( const PresentationSettingsEx& );
+ explicit PresentationSettingsEx( PresentationSettings const & );
+
+ /// @throws css::lang::IllegalArgumentException
+ void SetArguments( const css::uno::Sequence< css::beans::PropertyValue >& rArguments );
+
+ /// @throws css::lang::IllegalArgumentException
+ void SetPropertyValue( std::u16string_view rProperty, const css::uno::Any& rValue );
+};
+
+struct WrappedShapeEventImpl
+{
+ css::presentation::ClickAction meClickAction;
+ sal_Int32 mnVerb;
+ OUString maStrBookmark;
+ WrappedShapeEventImpl() : meClickAction( css::presentation::ClickAction_NONE ), mnVerb( 0 ) {};
+};
+
+typedef std::shared_ptr< WrappedShapeEventImpl > WrappedShapeEventImplPtr;
+
+class SlideShowListenerProxy :
+ public ::cppu::WeakImplHelper< css::presentation::XSlideShowNavigationListener, css::presentation::XShapeEventListener >
+{
+public:
+ SlideShowListenerProxy( rtl::Reference< SlideshowImpl > xController, css::uno::Reference< css::presentation::XSlideShow > xSlideShow );
+ virtual ~SlideShowListenerProxy() override;
+
+ void addAsSlideShowListener();
+ void removeAsSlideShowListener();
+
+ void addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener );
+ void removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener );
+
+ void addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape );
+ void removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape );
+
+ // css::animations::XAnimationListener
+ virtual void SAL_CALL beginEvent( const css::uno::Reference< css::animations::XAnimationNode >& Node ) override;
+ virtual void SAL_CALL endEvent( const css::uno::Reference< css::animations::XAnimationNode >& Node ) override;
+ virtual void SAL_CALL repeat( const css::uno::Reference< css::animations::XAnimationNode >& Node, ::sal_Int32 Repeat ) override;
+
+ // css::presentation::XSlideShowListener:
+ virtual void SAL_CALL paused() override;
+ virtual void SAL_CALL resumed() override;
+ virtual void SAL_CALL slideTransitionStarted() override;
+ virtual void SAL_CALL slideTransitionEnded() override;
+ virtual void SAL_CALL slideAnimationsEnded() override;
+ virtual void SAL_CALL slideEnded(sal_Bool bReverse) override;
+ virtual void SAL_CALL hyperLinkClicked(const OUString & hyperLink) override;
+
+ // css::presentation::XSlideShowNavigationListener:
+ virtual void SAL_CALL contextMenuShow(const css::awt::Point& point) override;
+
+ // css::lang::XEventListener:
+ virtual void SAL_CALL disposing(const css::lang::EventObject & Source) override;
+
+ // css::presentation::XShapeEventListener:
+ virtual void SAL_CALL click(const css::uno::Reference< css::drawing::XShape > & xShape, const css::awt::MouseEvent & aOriginalEvent) override;
+
+private:
+ std::mutex m_aMutex;
+ ::comphelper::OInterfaceContainerHelper4<css::presentation::XSlideShowListener> maListeners;
+ rtl::Reference< SlideshowImpl > mxController;
+ css::uno::Reference< css::presentation::XSlideShow > mxSlideShow;
+};
+
+typedef comphelper::WeakComponentImplHelper< css::presentation::XSlideShowController, css::container::XIndexAccess > SlideshowImplBase;
+
+class SlideshowImpl final : public SlideshowImplBase, public SfxListener
+{
+friend class SlideShow;
+friend class SlideShowView;
+
+public:
+ explicit SlideshowImpl( const css::uno::Reference< css::presentation::XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow);
+
+ // css::presentation::XSlideShowController:
+ virtual sal_Bool SAL_CALL getAlwaysOnTop() override;
+ virtual void SAL_CALL setAlwaysOnTop( sal_Bool _alwaysontop ) override;
+ virtual sal_Bool SAL_CALL getMouseVisible() override;
+ virtual void SAL_CALL setMouseVisible( sal_Bool _mousevisible ) override;
+ virtual sal_Bool SAL_CALL getUsePen() override;
+ virtual void SAL_CALL setUsePen( sal_Bool _usepen ) override;
+ virtual ::sal_Int32 SAL_CALL getPenColor() override;
+ virtual void SAL_CALL setPenColor( ::sal_Int32 _pencolor ) override;
+ virtual double SAL_CALL getPenWidth() override;
+ virtual void SAL_CALL setPenWidth( double dStrokeWidth ) override;
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setEraseAllInk( sal_Bool bEraseAllInk ) override;
+ virtual sal_Bool SAL_CALL isRunning( ) override;
+ virtual ::sal_Int32 SAL_CALL getSlideCount( ) override;
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getSlideByIndex( ::sal_Int32 Index ) override;
+ virtual void SAL_CALL addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener ) override;
+ virtual void SAL_CALL removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener ) override;
+ virtual void SAL_CALL gotoNextEffect( ) override;
+ virtual void SAL_CALL gotoPreviousEffect( ) override;
+ virtual void SAL_CALL gotoFirstSlide( ) override;
+ virtual void SAL_CALL gotoNextSlide( ) override;
+ virtual void SAL_CALL gotoPreviousSlide( ) override;
+ virtual void SAL_CALL gotoLastSlide( ) override;
+ virtual void SAL_CALL gotoBookmark( const OUString& Bookmark ) override;
+ virtual void SAL_CALL gotoSlide( const css::uno::Reference< css::drawing::XDrawPage >& Page ) override;
+ virtual void SAL_CALL gotoSlideIndex( ::sal_Int32 Index ) override;
+ virtual void SAL_CALL stopSound( ) override;
+ virtual void SAL_CALL pause( ) override;
+ virtual void SAL_CALL resume( ) override;
+ virtual sal_Bool SAL_CALL isPaused( ) override;
+ virtual void SAL_CALL blankScreen( ::sal_Int32 Color ) override;
+ virtual void SAL_CALL activate( ) override;
+ virtual void SAL_CALL deactivate( ) override;
+ virtual sal_Bool SAL_CALL isActive( ) override;
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getCurrentSlide( ) override;
+ virtual ::sal_Int32 SAL_CALL getCurrentSlideIndex( ) override;
+ virtual ::sal_Int32 SAL_CALL getNextSlideIndex( ) override;
+ virtual sal_Bool SAL_CALL isEndless( ) override;
+ virtual sal_Bool SAL_CALL isFullScreen( ) override;
+ virtual css::uno::Reference< css::presentation::XSlideShow > SAL_CALL getSlideShow( ) override;
+
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override;
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ // will be called from the SlideShowListenerProxy when this event is fired from the XSlideShow
+ void slideEnded(const bool bReverse);
+ void contextMenuShow(const css::awt::Point& point);
+ /// @throws css::uno::RuntimeException
+ void hyperLinkClicked(const OUString & hyperLink);
+ void click(const css::uno::Reference< css::drawing::XShape > & xShape);
+ bool swipe(const CommandGestureSwipeData &rSwipeData);
+ bool longpress(const CommandGestureLongPressData& rLongPressData);
+
+ /// ends the presentation async
+ void endPresentation();
+
+ // possibly triggered from events @SlideshowImpl::Notify if needed, but make it asynchronous to
+ // allow the noted event to completely finish in the core
+ void AsyncNotifyEvent(const css::uno::Reference< css::drawing::XDrawPage >&, const SdrHintKind);
+
+ ViewShell* getViewShell() const { return mpViewShell; }
+
+ void paint();
+ bool keyInput(const KeyEvent& rKEvt);
+ void mouseButtonUp(const MouseEvent& rMEvt);
+
+private:
+ SlideshowImpl(SlideshowImpl const &) = delete;
+ void operator =(SlideshowImpl const &) = delete;
+
+ virtual ~SlideshowImpl() override;
+
+ // override WeakComponentImplHelperBase::disposing()
+ // This function is called upon disposing the component,
+ // if your component needs special work when it becomes
+ // disposed, do it here.
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // internal
+ bool startShow( PresentationSettingsEx const * pPresSettings );
+ bool startPreview(
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode,
+ vcl::Window* pParent );
+
+ /** forces an async call to update in the main thread */
+ void startUpdateTimer();
+
+ void update();
+
+ void createSlideList( bool bAll, std::u16string_view rPresSlide );
+
+ void displayCurrentSlide (const bool bSkipAllMainSequenceEffects = false);
+
+ void displaySlideNumber( sal_Int32 nSlide );
+ void displaySlideIndex( sal_Int32 nIndex );
+ sal_Int32 getCurrentSlideNumber() const;
+ bool isInputFreezed() const { return mbInputFreeze; }
+
+ void jumpToBookmark( const OUString& sBookmark );
+
+ void hideChildWindows();
+ void showChildWindows();
+
+ void resize( const Size& rSize );
+
+ void setActiveXToolbarsVisible( bool bVisible );
+
+ DECL_LINK( updateHdl, Timer *, void );
+ DECL_LINK( ReadyForNextInputHdl, Timer *, void );
+ DECL_LINK( endPresentationHdl, void*, void );
+ void ContextMenuSelectHdl(std::u16string_view rIdent);
+ DECL_LINK( ContextMenuHdl, void*, void );
+ DECL_LINK( deactivateHdl, Timer *, void );
+ DECL_LINK( EventListenerHdl, VclSimpleEvent&, void );
+
+ /** called only by the slideshow view when the first paint event occurs.
+ This actually starts the slideshow. */
+ void onFirstPaint();
+
+ ::tools::Long getRestoreSlide() const { return mnRestoreSlide; }
+
+private:
+ bool startShowImpl(
+ const css::uno::Sequence< css::beans::PropertyValue >& aProperties );
+
+ SfxViewFrame* getViewFrame() const;
+ SfxDispatcher* getDispatcher() const;
+ SfxBindings* getBindings() const;
+
+ sal_Int32 getSlideNumberForBookmark( const OUString& rStrBookmark );
+
+ void removeShapeEvents();
+ void registerShapeEvents( sal_Int32 nSlideNumber );
+ /// @throws css::uno::Exception
+ void registerShapeEvents( css::uno::Reference< css::drawing::XShapes > const & xShapes );
+
+ static css::uno::Reference< css::presentation::XSlideShow > createSlideShow();
+
+ static void setAutoSaveState( bool bOn );
+ void gotoPreviousSlide (const bool bSkipAllMainSequenceEffects);
+
+ /** Called by our maUpdateTimer's updateHdl handler this method is
+ responsible to call the slideshow update() method and, depending on
+ its return value, wait for a certain amount of time before another
+ call to update() is scheduled.
+ */
+ void updateSlideShow();
+
+ css::uno::Reference< css::presentation::XSlideShow > mxShow;
+ rtl::Reference<sd::SlideShowView> mxView;
+ css::uno::Reference< css::frame::XModel > mxModel;
+
+ Timer maUpdateTimer;
+ Timer maInputFreezeTimer;
+ Timer maDeactivateTimer;
+
+ ::sd::View* mpView;
+ ViewShell* mpViewShell;
+ DrawDocShell* mpDocSh;
+ SdDrawDocument* mpDoc;
+
+ VclPtr<vcl::Window> mpParentWindow;
+ VclPtr<sd::ShowWindow> mpShowWindow;
+
+ std::shared_ptr< AnimationSlideController > mpSlideController;
+
+ ::tools::Long mnRestoreSlide;
+ Point maPopupMousePos;
+ Size maPresSize;
+ AnimationMode meAnimationMode;
+ OUString maCharBuffer;
+ VclPtr< ::sd::Window> mpOldActiveWindow;
+ Link<StarBASIC*,bool> maStarBASICGlobalErrorHdl;
+ ::tools::ULong mnChildMask;
+ bool mbDisposed;
+ bool mbAutoSaveWasOn;
+ bool mbRehearseTimings;
+ bool mbIsPaused;
+ bool mbWasPaused; // used to cache pause state during context menu
+ bool mbInputFreeze;
+ bool mbActive;
+
+ PresentationSettings maPresSettings;
+ sal_Int32 mnUserPaintColor;
+
+ bool mbUsePen;
+ double mdUserPaintStrokeWidth;
+
+ std::map< css::uno::Reference< css::drawing::XShape >, WrappedShapeEventImplPtr >
+ maShapeEventMap;
+
+ css::uno::Reference< css::drawing::XDrawPage > mxPreviewDrawPage;
+ css::uno::Reference< css::animations::XAnimationNode > mxPreviewAnimationNode;
+
+ css::uno::Reference< css::media::XPlayer > mxPlayer;
+
+ ::std::unique_ptr<PaneHider> mpPaneHider;
+
+ ImplSVEvent * mnEndShowEvent;
+ ImplSVEvent * mnContextMenuEvent;
+ ImplSVEvent * mnEventObjectChange;
+ ImplSVEvent * mnEventPageOrderChange;
+
+ css::uno::Reference< css::presentation::XPresentation2 > mxPresentation;
+ ::rtl::Reference< SlideShowListenerProxy > mxListenerProxy;
+};
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowviewimpl.cxx b/sd/source/ui/slideshow/slideshowviewimpl.cxx
new file mode 100644
index 0000000000..d6addc3f87
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowviewimpl.cxx
@@ -0,0 +1,626 @@
+/* -*- 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 "slideshowviewimpl.hxx"
+#include "slideshowimpl.hxx"
+#include <sdpage.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/awt/Pointer.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <basegfx/utils/canvastools.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::WeakReference;
+using ::com::sun::star::uno::Exception;
+
+using namespace ::com::sun::star;
+
+namespace sd
+{
+
+void SlideShowViewMouseListeners::notify( std::unique_lock<std::mutex>& rGuard, const WrappedMouseEvent& rEvent )
+{
+ forEach(rGuard,
+ [&rEvent] (const Reference<css::awt::XMouseListener>& rListener)
+ {
+ switch( rEvent.meType )
+ {
+ case WrappedMouseEvent::PRESSED:
+ rListener->mousePressed( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::RELEASED:
+ rListener->mouseReleased( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::ENTERED:
+ rListener->mouseEntered( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::EXITED:
+ rListener->mouseExited( rEvent.maEvent );
+ break;
+ }
+ });
+}
+
+
+void SlideShowViewMouseMotionListeners::notify( std::unique_lock<std::mutex>& rGuard,const WrappedMouseMotionEvent& rEvent )
+{
+ forEach(rGuard,
+ [&rEvent] (const Reference< awt::XMouseMotionListener >& rListener)
+ {
+ switch( rEvent.meType )
+ {
+ case WrappedMouseMotionEvent::DRAGGED:
+ rListener->mouseDragged( rEvent.maEvent );
+ break;
+
+ case WrappedMouseMotionEvent::MOVED:
+ rListener->mouseMoved( rEvent.maEvent );
+ break;
+ }
+ });
+}
+
+// SlideShowView
+SlideShowView::SlideShowView( ShowWindow& rOutputWindow,
+ SdDrawDocument* pDoc,
+ AnimationMode eAnimationMode,
+ SlideshowImpl* pSlideShow,
+ bool bFullScreen )
+: mpCanvas( ::cppcanvas::VCLFactory::createSpriteCanvas( rOutputWindow ) ),
+ mxWindow( VCLUnoHelper::GetInterface( &rOutputWindow ), uno::UNO_SET_THROW ),
+ mxWindowPeer( mxWindow, uno::UNO_QUERY_THROW ),
+ mpSlideShow( pSlideShow ),
+ mrOutputWindow( rOutputWindow ),
+ mpDoc( pDoc ),
+ mbIsMouseMotionListener( false ),
+ meAnimationMode( eAnimationMode ),
+ mbFirstPaint( true ),
+ mbMousePressedEaten( false )
+{
+ mxWindow->addWindowListener( this );
+ mxWindow->addMouseListener( this );
+
+ mxPointer = awt::Pointer::create( ::comphelper::getProcessComponentContext() );
+
+ getTransformation();
+
+ // #i48939# only switch on kind of hacky scroll optimization, when
+ // running fullscreen. this minimizes the probability that other
+ // windows partially cover the show.
+ if( bFullScreen )
+ {
+ try
+ {
+ Reference< beans::XPropertySet > xCanvasProps( getCanvas(),
+ uno::UNO_QUERY_THROW );
+ xCanvasProps->setPropertyValue("UnsafeScrolling",
+ uno::Any( true ) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ mTranslationOffset.Width = 0;
+ mTranslationOffset.Height = 0;
+}
+
+// Dispose all internal references
+void SlideShowView::disposing(std::unique_lock<std::mutex>& rGuard)
+{
+ mpSlideShow = nullptr;
+
+ // deregister listeners
+ if( mxWindow.is() )
+ {
+ mxWindow->removeWindowListener( this );
+ mxWindow->removeMouseListener( this );
+
+ if( mbIsMouseMotionListener )
+ mxWindow->removeMouseMotionListener( this );
+ }
+
+ mpCanvas.reset();
+ mxWindow.clear();
+
+ // clear all listener containers
+ disposingImpl(rGuard);
+}
+
+// Disposing our broadcaster
+void SAL_CALL SlideShowView::disposing( const lang::EventObject& )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ disposingImpl(aGuard);
+}
+
+// Disposing our broadcaster
+void SlideShowView::disposingImpl(std::unique_lock<std::mutex>& rGuard)
+{
+ // notify all listeners that _we_ are going down (send a disposing()),
+ // then delete listener containers:
+ lang::EventObject const evt( static_cast<OWeakObject *>(this) );
+ if (!maViewListeners.empty())
+ {
+ auto tmp = std::move(maViewListeners);
+ rGuard.unlock();
+ for( const auto& rxListener : tmp )
+ {
+ Reference< util::XModifyListener > xListener( rxListener );
+ if( xListener.is() )
+ xListener->disposing( evt );
+ }
+ rGuard.lock();
+ }
+ if (maPaintListeners.getLength(rGuard))
+ {
+ maPaintListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+ if (maMouseListeners.getLength(rGuard))
+ {
+ maMouseListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+ if (maMouseMotionListeners.getLength(rGuard))
+ {
+ maMouseMotionListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+}
+
+void SlideShowView::paint( const awt::PaintEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( mbFirstPaint )
+ {
+ mbFirstPaint = false;
+ SlideshowImpl* pSlideShow = mpSlideShow;
+ aGuard.unlock();
+ if( pSlideShow )
+ pSlideShow->onFirstPaint();
+ }
+ else
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ awt::PaintEvent aEvent( e );
+ aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+ maPaintListeners.notifyEach( aGuard, &css::awt::XPaintListener::windowPaint, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+// XSlideShowView methods
+Reference< rendering::XSpriteCanvas > SAL_CALL SlideShowView::getCanvas( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ return mpCanvas ? mpCanvas->getUNOSpriteCanvas() : Reference< rendering::XSpriteCanvas >();
+}
+
+void SAL_CALL SlideShowView::clear()
+{
+ // paint background in black
+ std::unique_lock aGuard( m_aMutex );
+ SolarMutexGuard aSolarGuard;
+
+ // fill the bounds rectangle in black
+
+ const Size aWindowSize( mrOutputWindow.GetSizePixel() );
+
+ ::basegfx::B2DPolygon aPoly( ::basegfx::utils::createPolygonFromRect(
+ ::basegfx::B2DRectangle(0.0,0.0,
+ aWindowSize.Width(),
+ aWindowSize.Height() ) ) );
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::createPolyPolygon( mpCanvas, aPoly ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->setRGBAFillColor( 0x000000FFU );
+ pPolyPoly->draw();
+ }
+}
+
+geometry::IntegerSize2D SAL_CALL SlideShowView::getTranslationOffset( )
+{
+ return mTranslationOffset;
+}
+
+geometry::AffineMatrix2D SAL_CALL SlideShowView::getTransformation( )
+{
+ std::unique_lock aGuard( m_aMutex );
+ SolarMutexGuard aSolarGuard;
+
+ const Size& rTmpSize( mrOutputWindow.GetSizePixel() );
+
+ if (rTmpSize.IsEmpty())
+ {
+ return geometry::AffineMatrix2D (1,0,0,0,1,0);
+ }
+
+ const Size aWindowSize( mrOutputWindow.GetSizePixel() );
+ Size aOutputSize( aWindowSize );
+
+ if( meAnimationMode != ANIMATIONMODE_SHOW )
+ {
+ aOutputSize.setWidth( static_cast<::tools::Long>( aOutputSize.Width() / 1.03 ) );
+ aOutputSize.setHeight( static_cast<::tools::Long>( aOutputSize.Height() / 1.03 ) );
+ }
+
+ SdPage* pP = mpDoc->GetSdPage( 0, PageKind::Standard );
+ Size aPageSize( pP->GetSize() );
+
+ const double page_ratio = static_cast<double>(aPageSize.Width()) / static_cast<double>(aPageSize.Height());
+ const double output_ratio = static_cast<double>(aOutputSize.Width()) / static_cast<double>(aOutputSize.Height());
+
+ if( page_ratio > output_ratio )
+ {
+ aOutputSize.setHeight( ( aOutputSize.Width() * aPageSize.Height() ) / aPageSize.Width() );
+ }
+ else if( page_ratio < output_ratio )
+ {
+ aOutputSize.setWidth( ( aOutputSize.Height() * aPageSize.Width() ) / aPageSize.Height() );
+ }
+
+ Point aOutputOffset( ( aWindowSize.Width() - aOutputSize.Width() ) >> 1,
+ ( aWindowSize.Height() - aOutputSize.Height() ) >> 1 );
+
+ // Reduce available width by one, as the slides might actually
+ // render one pixel wider and higher as aPageSize below specifies
+ // (when shapes of page size have visible border lines)
+ aOutputSize.AdjustWidth( -1 );
+ aOutputSize.AdjustHeight( -1 );
+
+ // Record mTranslationOffset
+ mTranslationOffset.Height = aOutputOffset.Y();
+ mTranslationOffset.Width = aOutputOffset.X();
+
+ // scale presentation into available window rect (minus 10%); center in the window
+ const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aOutputSize.Width(), aOutputSize.Height(), aOutputOffset.X(), aOutputOffset.Y()));
+
+ geometry::AffineMatrix2D aRes;
+
+ return ::basegfx::unotools::affineMatrixFromHomMatrix( aRes, aMatrix );
+}
+
+void SAL_CALL SlideShowView::addTransformationChangedListener( const Reference< util::XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+ WeakReference< util::XModifyListener > xWeak( xListener );
+ if( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) == maViewListeners.end() )
+ maViewListeners.push_back( xWeak );
+}
+
+void SAL_CALL SlideShowView::removeTransformationChangedListener( const Reference< util::XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+ WeakReference< util::XModifyListener > xWeak( xListener );
+ auto aIter( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) );
+ if( aIter != maViewListeners.end() )
+ maViewListeners.erase( aIter );
+}
+
+void SAL_CALL SlideShowView::addPaintListener( const Reference< awt::XPaintListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maPaintListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removePaintListener( const Reference< awt::XPaintListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maPaintListeners.removeInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::addMouseListener( const Reference< awt::XMouseListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removeMouseListener( const Reference< awt::XMouseListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseListeners.removeInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::addMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+
+ if( !mbIsMouseMotionListener && mxWindow.is() )
+ {
+ // delay motion event registration, until we really
+ // need it
+ mbIsMouseMotionListener = true;
+ mxWindow->addMouseMotionListener( this );
+ }
+
+ maMouseMotionListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removeMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseMotionListeners.removeInterface( aGuard, xListener );
+
+ // TODO(P1): Might be nice to deregister for mouse motion
+ // events, when the last listener is gone.
+}
+
+void SAL_CALL SlideShowView::setMouseCursor( sal_Int16 nPointerShape )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ // forward to window
+ if( mxPointer.is() )
+ mxPointer->setType( nPointerShape );
+
+ if( mxWindowPeer.is() )
+ mxWindowPeer->setPointer( mxPointer );
+}
+
+awt::Rectangle SAL_CALL SlideShowView::getCanvasArea( )
+{
+ awt::Rectangle aRectangle;
+
+ if( mxWindow.is() )
+ return mxWindow->getPosSize();
+
+ aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0;
+
+ return aRectangle;
+}
+
+void SlideShowView::updateimpl( std::unique_lock<std::mutex>& rGuard, SlideshowImpl* pSlideShow )
+{
+ if( !pSlideShow )
+ return;
+
+ ::rtl::Reference< SlideshowImpl > xKeepAlive( pSlideShow );
+
+ if( mbFirstPaint )
+ {
+ mbFirstPaint = false;
+ SlideshowImpl* pTmpSlideShow = mpSlideShow;
+ rGuard.unlock();
+ if( pTmpSlideShow )
+ pTmpSlideShow->onFirstPaint();
+ } else
+ rGuard.unlock();
+
+ pSlideShow->startUpdateTimer();
+}
+
+// XWindowListener methods
+void SAL_CALL SlideShowView::windowResized( const awt::WindowEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+
+ if (!maViewListeners.empty())
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ awt::WindowEvent aEvent( e );
+ aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+ auto aIter( maViewListeners.begin() );
+ while( aIter != maViewListeners.end() )
+ {
+ Reference< util::XModifyListener > xListener( *aIter );
+ if( xListener.is() )
+ {
+ aGuard.unlock();
+ xListener->modified( aEvent );
+ aGuard.lock();
+ ++aIter;
+ }
+ else
+ {
+ aIter = maViewListeners.erase( aIter );
+ }
+ }
+ }
+
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::windowMoved( const awt::WindowEvent& )
+{
+ // ignored
+}
+
+void SAL_CALL SlideShowView::windowShown( const lang::EventObject& )
+{
+ // ignored
+}
+
+void SAL_CALL SlideShowView::windowHidden( const lang::EventObject& )
+{
+ // ignored
+}
+
+// XMouseListener implementation
+void SAL_CALL SlideShowView::mousePressed( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ if( mpSlideShow && mpSlideShow->isInputFreezed() )
+ {
+ mbMousePressedEaten = true;
+ }
+ else
+ {
+ mbMousePressedEaten = false;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::PRESSED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+void SAL_CALL SlideShowView::mouseReleased( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ if( mbMousePressedEaten )
+ {
+ // if mouse button down was ignored, also ignore mouse button up
+ mbMousePressedEaten = false;
+ }
+ else if( mpSlideShow && !mpSlideShow->isInputFreezed() )
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::RELEASED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+void SAL_CALL SlideShowView::mouseEntered( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::ENTERED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::mouseExited( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::EXITED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+// XMouseMotionListener implementation
+void SAL_CALL SlideShowView::mouseDragged( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseMotionEvent aEvent;
+ aEvent.meType = WrappedMouseMotionEvent::DRAGGED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseMotionListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::mouseMoved( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseMotionEvent aEvent;
+ aEvent.meType = WrappedMouseMotionEvent::MOVED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseMotionListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowviewimpl.hxx b/sd/source/ui/slideshow/slideshowviewimpl.hxx
new file mode 100644
index 0000000000..3a5018be41
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowviewimpl.hxx
@@ -0,0 +1,182 @@
+/* -*- 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 <comphelper/compbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/awt/XPaintListener.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+#include <cppcanvas/spritecanvas.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <slideshow.hxx>
+
+namespace com::sun::star::awt { class XPointer; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::awt { class XWindowPeer; }
+namespace com::sun::star::awt { struct WindowEvent; }
+namespace com::sun::star::rendering { class XSpriteCanvas; }
+class SdDrawDocument;
+
+namespace sd
+{
+
+struct WrappedMouseEvent : public css::lang::EventObject
+{
+ enum EventType
+ {
+ PRESSED,
+ RELEASED,
+ ENTERED,
+ EXITED
+ };
+
+ EventType meType;
+ css::awt::MouseEvent maEvent;
+};
+
+struct WrappedMouseMotionEvent : public css::lang::EventObject
+{
+ enum EventType
+ {
+ DRAGGED,
+ MOVED
+ };
+
+ EventType meType;
+ css::awt::MouseEvent maEvent;
+};
+
+// SlideShowViewPaintListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XPaintListener > SlideShowViewPaintListeners;
+
+
+// SlideShowViewMouseListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XMouseListener > SlideShowViewMouseListeners_Base;
+
+class SlideShowViewMouseListeners : public SlideShowViewMouseListeners_Base
+{
+public:
+ void notify(std::unique_lock<std::mutex>& rGuard, const WrappedMouseEvent& rEvent);
+};
+
+
+// SlideShowViewMouseMotionListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XMouseMotionListener > SlideShowViewMouseMotionListeners_Base;
+
+class SlideShowViewMouseMotionListeners : public SlideShowViewMouseMotionListeners_Base
+{
+public:
+ void notify( std::unique_lock<std::mutex>& rGuard, const WrappedMouseMotionEvent& rEvent );
+};
+
+// SlideShowView
+class ShowWindow;
+class SlideshowImpl;
+
+typedef comphelper::WeakComponentImplHelper< css::presentation::XSlideShowView,
+ css::awt::XWindowListener,
+ css::awt::XMouseListener,
+ css::awt::XMouseMotionListener > SlideShowView_Base;
+
+class SlideShowView final : public SlideShowView_Base
+{
+public:
+ SlideShowView( ShowWindow& rOutputWindow,
+ SdDrawDocument* pDoc,
+ AnimationMode eAnimationMode,
+ SlideshowImpl* pSlideShow,
+ bool bFullScreen );
+
+ void ignoreNextMouseReleased() { mbMousePressedEaten = true; }
+
+ /// Dispose all internal references
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ /// Disposing our broadcaster
+ virtual void SAL_CALL disposing( const css::lang::EventObject& ) override;
+
+ /// @throws css::uno::RuntimeException
+ void paint( const css::awt::PaintEvent& e );
+
+ // XSlideShowView methods
+ virtual css::uno::Reference< css::rendering::XSpriteCanvas > SAL_CALL getCanvas( ) override;
+ virtual void SAL_CALL clear( ) override;
+ virtual css::geometry::AffineMatrix2D SAL_CALL getTransformation( ) override;
+ virtual css::geometry::IntegerSize2D SAL_CALL getTranslationOffset( ) override;
+ virtual void SAL_CALL addTransformationChangedListener( const css::uno::Reference< css::util::XModifyListener >& xListener ) override;
+ virtual void SAL_CALL removeTransformationChangedListener( const css::uno::Reference< css::util::XModifyListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL setMouseCursor( sal_Int16 nPointerShape ) override;
+ virtual css::awt::Rectangle SAL_CALL getCanvasArea( ) override;
+
+ // XWindowListener methods
+ virtual void SAL_CALL windowResized( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const css::lang::EventObject& e ) override;
+
+ // XMouseListener implementation
+ 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 implementation
+ virtual void SAL_CALL mouseDragged( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseMoved( const css::awt::MouseEvent& e ) override;
+
+protected:
+ virtual ~SlideShowView() override {}
+
+private:
+ void updateimpl( std::unique_lock<std::mutex>& rGuard, SlideshowImpl* pSlideShow );
+
+ void disposingImpl( std::unique_lock<std::mutex>& );
+
+ ::cppcanvas::SpriteCanvasSharedPtr mpCanvas;
+ css::uno::Reference< css::awt::XWindow > mxWindow;
+ css::uno::Reference< css::awt::XWindowPeer > mxWindowPeer;
+ css::uno::Reference< css::awt::XPointer > mxPointer;
+ SlideshowImpl* mpSlideShow;
+ ShowWindow& mrOutputWindow;
+ std::vector< css::uno::WeakReference< css::util::XModifyListener > >
+ maViewListeners;
+ SlideShowViewPaintListeners maPaintListeners;
+ SlideShowViewMouseListeners maMouseListeners;
+ SlideShowViewMouseMotionListeners maMouseMotionListeners;
+ SdDrawDocument* mpDoc;
+ bool mbIsMouseMotionListener;
+ AnimationMode meAnimationMode;
+ bool mbFirstPaint;
+ bool mbMousePressedEaten;
+ css::geometry::IntegerSize2D mTranslationOffset;
+};
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */