1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/diagnose_ex.h>
23 #include <cppuhelper/basemutex.hxx>
24 #include <cppuhelper/compbase.hxx>
25 #include <cppuhelper/interfacecontainer.h>
26 #include <cppuhelper/supportsservice.hxx>
28 #include <comphelper/scopeguard.hxx>
29 #include <comphelper/storagehelper.hxx>
30 #include <cppcanvas/polypolygon.hxx>
31 #include <osl/thread.hxx>
33 #include <tools/debug.hxx>
35 #include <basegfx/point/b2dpoint.hxx>
36 #include <basegfx/polygon/b2dpolygon.hxx>
37 #include <basegfx/utils/canvastools.hxx>
39 #include <sal/log.hxx>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/util/XUpdatable.hpp>
43 #include <com/sun/star/awt/SystemPointer.hpp>
44 #include <com/sun/star/presentation/XSlideShow.hpp>
45 #include <com/sun/star/presentation/XSlideShowListener.hpp>
46 #include <com/sun/star/lang/NoSupportException.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/lang/XServiceInfo.hpp>
49 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
50 #include <com/sun/star/drawing/PointSequence.hpp>
51 #include <com/sun/star/drawing/XLayer.hpp>
52 #include <com/sun/star/drawing/XLayerSupplier.hpp>
53 #include <com/sun/star/drawing/XLayerManager.hpp>
54 #include <com/sun/star/container/XNameAccess.hpp>
55 #include <com/sun/star/document/XStorageBasedDocument.hpp>
57 #include <com/sun/star/uno/Reference.hxx>
58 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
60 #include <unoviewcontainer.hxx>
61 #include <transitionfactory.hxx>
62 #include <eventmultiplexer.hxx>
63 #include <usereventqueue.hxx>
64 #include <eventqueue.hxx>
65 #include <cursormanager.hxx>
66 #include <mediafilemanager.hxx>
67 #include <slideshowcontext.hxx>
68 #include <activitiesqueue.hxx>
69 #include <activitiesfactory.hxx>
70 #include <interruptabledelayevent.hxx>
72 #include <shapemaps.hxx>
73 #include <slideview.hxx>
75 #include <unoview.hxx>
76 #include "rehearsetimingsactivity.hxx"
77 #include "waitsymbol.hxx"
78 #include "effectrewinder.hxx"
79 #include <framerate.hxx>
80 #include "pointersymbol.hxx"
86 using namespace com::sun::star
;
87 using namespace ::slideshow::internal
;
89 namespace box2d::utils
{ class box2DWorld
;
90 typedef ::std::shared_ptr
< box2DWorld
> Box2DWorldSharedPtr
; }
94 /** During animations the update() method tells its caller to call it as
95 soon as possible. This gives us more time to render the next frame and
96 still maintain a steady frame rate. This class is responsible for
97 synchronizing the display of new frames and thus keeping the frame rate
100 class FrameSynchronization
103 /** Create new object with a predefined duration between two frames.
104 @param nFrameDuration
105 The preferred duration between the display of two frames in
108 explicit FrameSynchronization (const double nFrameDuration
);
110 /** Set the current time as the time at which the current frame is
111 displayed. From this the target time of the next frame is derived.
113 void MarkCurrentFrame();
115 /** When there is time left until the next frame is due then wait.
116 Otherwise return without delay.
120 /** Activate frame synchronization when an animation is active and
121 frames are to be displayed in a steady rate. While active
122 Synchronize() will wait until the frame duration time has passed.
126 /** Deactivate frame synchronization when no animation is active and the
127 time between frames depends on user actions and other external
128 sources. While deactivated Synchronize() will return without delay.
133 /** The timer that is used for synchronization is independent from the
134 one used by SlideShowImpl: it is not paused or modified by
137 canvas::tools::ElapsedTime maTimer
;
138 /** Time between the display of frames. Enforced only when mbIsActive
141 const double mnFrameDuration
;
142 /** Time (of maTimer) when the next frame shall be displayed.
143 Synchronize() will wait until this time.
145 double mnNextFrameTargetTime
;
146 /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
147 it returns immediately.
152 /******************************************************************************
156 This class encapsulates the slideshow presentation viewer.
158 With an instance of this class, it is possible to statically
159 and dynamically show a presentation, as defined by the
160 constructor-provided draw model (represented by a sequence
161 of css::drawing::XDrawPage objects).
163 It is possible to show the presentation on multiple views
164 simultaneously (e.g. for a multi-monitor setup). Since this
165 class also relies on user interaction, the corresponding
166 XSlideShowView interface provides means to register some UI
167 event listeners (mostly borrowed from awt::XWindow interface).
169 Since currently (mid 2004), OOo isn't very well suited to
170 multi-threaded rendering, this class relies on <em>very
171 frequent</em> external update() calls, which will render the
172 next frame of animations. This works as follows: after the
173 displaySlide() has been successfully called (which setup and
174 starts an actual slide show), the update() method must be
175 called until it returns false.
176 Effectively, this puts the burden of providing
177 concurrency to the clients of this class, which, as noted
178 above, is currently unavoidable with the current state of
179 affairs (I've actually tried threading here, but failed
180 miserably when using the VCL canvas as the render backend -
183 ******************************************************************************/
185 typedef cppu::WeakComponentImplHelper
<css::lang::XServiceInfo
, presentation::XSlideShow
> SlideShowImplBase
;
187 typedef ::std::vector
< ::cppcanvas::PolyPolygonSharedPtr
> PolyPolygonVector
;
189 /// Maps XDrawPage for annotations persistence
190 typedef ::std::map
< css::uno::Reference
<
191 css::drawing::XDrawPage
>,
192 PolyPolygonVector
> PolygonMap
;
194 class SlideShowImpl
: private cppu::BaseMutex
,
195 public CursorManager
,
196 public MediaFileManager
,
197 public SlideShowImplBase
200 explicit SlideShowImpl(
201 uno::Reference
<uno::XComponentContext
> const& xContext
);
203 /** Notify that the transition phase of the current slide
206 The life of a slide has three phases: the transition
207 phase, when the previous slide vanishes, and the
208 current slide becomes visible, the shape animation
209 phase, when shape effects are running, and the phase
210 after the last shape animation has ended, but before
211 the next slide transition starts.
213 This method notifies the end of the first phase.
216 When true, Slide::show() is passed a true as well, denoting
217 explicit paint of slide content. Pass false here, if e.g. a
218 slide transition has already rendered the initial slide image.
220 void notifySlideTransitionEnded( bool bPaintSlide
);
222 /** Notify that the shape animation phase of the current slide
225 The life of a slide has three phases: the transition
226 phase, when the previous slide vanishes, and the
227 current slide becomes visible, the shape animation
228 phase, when shape effects are running, and the phase
229 after the last shape animation has ended, but before
230 the next slide transition starts.
232 This method notifies the end of the second phase.
234 void notifySlideAnimationsEnded();
236 /** Notify that the slide has ended.
238 The life of a slide has three phases: the transition
239 phase, when the previous slide vanishes, and the
240 current slide becomes visible, the shape animation
241 phase, when shape effects are running, and the phase
242 after the last shape animation has ended, but before
243 the next slide transition starts.
245 This method notifies the end of the third phase.
247 void notifySlideEnded (const bool bReverse
);
249 /** Notification from eventmultiplexer that a hyperlink
252 bool notifyHyperLinkClicked( OUString
const& hyperLink
);
254 /** Notification from eventmultiplexer that an animation event has occurred.
255 This will be forwarded to all registered XSlideShowListener
257 bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
);
259 /** Obtain a MediaTempFile for the specified url. */
260 virtual std::shared_ptr
<avmedia::MediaTempFile
> getMediaTempFile(const OUString
& aUrl
) override
;
264 virtual OUString SAL_CALL
getImplementationName() override
;
265 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
266 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames () override
;
269 virtual sal_Bool SAL_CALL
nextEffect() override
;
270 virtual sal_Bool SAL_CALL
previousEffect() override
;
271 virtual sal_Bool SAL_CALL
startShapeActivity(
272 uno::Reference
<drawing::XShape
> const& xShape
) override
;
273 virtual sal_Bool SAL_CALL
stopShapeActivity(
274 uno::Reference
<drawing::XShape
> const& xShape
) override
;
275 virtual sal_Bool SAL_CALL
pause( sal_Bool bPauseShow
) override
;
276 virtual uno::Reference
<drawing::XDrawPage
> SAL_CALL
getCurrentSlide() override
;
277 virtual void SAL_CALL
displaySlide(
278 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
279 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
280 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
281 uno::Sequence
<beans::PropertyValue
> const& rProperties
) override
;
282 virtual void SAL_CALL
registerUserPaintPolygons( const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xDocFactory
) override
;
283 virtual sal_Bool SAL_CALL
setProperty(
284 beans::PropertyValue
const& rProperty
) override
;
285 virtual sal_Bool SAL_CALL
addView(
286 uno::Reference
<presentation::XSlideShowView
> const& xView
) override
;
287 virtual sal_Bool SAL_CALL
removeView(
288 uno::Reference
<presentation::XSlideShowView
> const& xView
) override
;
289 virtual sal_Bool SAL_CALL
update( double & nNextTimeout
) override
;
290 virtual void SAL_CALL
addSlideShowListener(
291 uno::Reference
<presentation::XSlideShowListener
> const& xListener
) override
;
292 virtual void SAL_CALL
removeSlideShowListener(
293 uno::Reference
<presentation::XSlideShowListener
> const& xListener
) override
;
294 virtual void SAL_CALL
addShapeEventListener(
295 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
296 uno::Reference
<drawing::XShape
> const& xShape
) override
;
297 virtual void SAL_CALL
removeShapeEventListener(
298 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
299 uno::Reference
<drawing::XShape
> const& xShape
) override
;
300 virtual void SAL_CALL
setShapeCursor(
301 uno::Reference
<drawing::XShape
> const& xShape
, sal_Int16 nPointerShape
) override
;
306 virtual bool requestCursor( sal_Int16 nCursorShape
) override
;
307 virtual void resetCursor() override
;
309 /** This is somewhat similar to displaySlide when called for the current
310 slide. It has been simplified to take advantage of that no slide
311 change takes place. Furthermore it does not show the slide
314 void redisplayCurrentSlide();
317 // WeakComponentImplHelperBase
318 virtual void SAL_CALL
disposing() override
;
320 bool isDisposed() const
322 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
326 struct SeparateListenerImpl
; friend struct SeparateListenerImpl
;
327 class PrefetchPropertiesFunc
; friend class PrefetchPropertiesFunc
;
329 /// Stop currently running show.
332 ///Find a polygons vector in maPolygons (map)
333 PolygonMap::iterator
findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
);
335 /// Creates a new slide.
336 SlideSharedPtr
makeSlide(
337 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
338 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
339 uno::Reference
<animations::XAnimationNode
> const& xRootNode
);
341 /// Checks whether the given slide/animation node matches mpPrefetchSlide
343 SlideSharedPtr
const& pSlide
,
344 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
345 uno::Reference
<animations::XAnimationNode
> const& xNode
)
348 return (pSlide
->getXDrawPage() == xSlide
&&
349 pSlide
->getXAnimationNode() == xNode
);
351 return (!xSlide
.is() && !xNode
.is());
354 /// Resets the current slide transition sound object with a new one:
355 SoundPlayerSharedPtr
resetSlideTransitionSound(
356 uno::Any
const& url
, bool bLoopSound
);
358 /// stops the current slide transition sound
359 void stopSlideTransitionSound();
361 /** Prepare a slide transition
363 This method registers all necessary events and
364 activities for a slide transition.
366 @return the slide change activity, or NULL for no transition effect
368 ActivitySharedPtr
createSlideTransition(
369 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
370 const SlideSharedPtr
& rLeavingSlide
,
371 const SlideSharedPtr
& rEnteringSlide
,
372 const EventSharedPtr
& rTransitionEndEvent
);
374 /** Request/release the wait symbol. The wait symbol is displayed when
375 there are more requests then releases. Locking the wait symbol
376 helps to avoid intermediate repaints.
378 Do not call this method directly. Use WaitSymbolLock instead.
380 void requestWaitSymbol();
381 void releaseWaitSymbol();
383 class WaitSymbolLock
{public:
384 explicit WaitSymbolLock(SlideShowImpl
& rSlideShowImpl
) : mrSlideShowImpl(rSlideShowImpl
)
385 { mrSlideShowImpl
.requestWaitSymbol(); }
387 { mrSlideShowImpl
.releaseWaitSymbol(); }
388 private: SlideShowImpl
& mrSlideShowImpl
;
391 /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
392 sal_Int16
calcActiveCursor( sal_Int16 nCursorShape
) const;
394 /** This method is called asynchronously to finish the rewinding of an
395 effect to the previous slide that was initiated earlier.
397 void rewindEffectToPreviousSlide();
399 /// all registered views
400 UnoViewContainer maViewContainer
;
402 /// all registered slide show listeners
403 comphelper::OInterfaceContainerHelper2 maListenerContainer
;
405 /// map of vectors, containing all registered listeners for a shape
406 ShapeEventListenerMap maShapeEventListeners
;
407 /// map of sal_Int16 values, specifying the mouse cursor for every shape
408 ShapeCursorMap maShapeCursors
;
410 //map of vector of Polygons, containing polygons drawn on each slide.
411 PolygonMap maPolygons
;
413 std::optional
<RGBColor
> maUserPaintColor
;
415 double maUserPaintStrokeWidth
;
417 //changed for the eraser project
418 std::optional
<bool> maEraseAllInk
;
419 std::optional
<sal_Int32
> maEraseInk
;
422 std::shared_ptr
<canvas::tools::ElapsedTime
> mpPresTimer
;
423 ScreenUpdater maScreenUpdater
;
424 EventQueue maEventQueue
;
425 EventMultiplexer maEventMultiplexer
;
426 ActivitiesQueue maActivitiesQueue
;
427 UserEventQueue maUserEventQueue
;
428 SubsettableShapeManagerSharedPtr mpDummyPtr
;
429 box2d::utils::Box2DWorldSharedPtr mpBox2DDummyPtr
;
431 std::shared_ptr
<SeparateListenerImpl
> mpListener
;
433 std::shared_ptr
<RehearseTimingsActivity
> mpRehearseTimingsActivity
;
434 std::shared_ptr
<WaitSymbol
> mpWaitSymbol
;
436 std::shared_ptr
<PointerSymbol
> mpPointerSymbol
;
438 /// the current slide transition sound object:
439 SoundPlayerSharedPtr mpCurrentSlideTransitionSound
;
441 uno::Reference
<uno::XComponentContext
> mxComponentContext
;
443 presentation::XTransitionFactory
> mxOptionalTransitionFactory
;
445 /// the previously running slide
446 SlideSharedPtr mpPreviousSlide
;
447 /// the currently running slide
448 SlideSharedPtr mpCurrentSlide
;
449 /// the already prefetched slide: best candidate for upcoming slide
450 SlideSharedPtr mpPrefetchSlide
;
451 /// slide to be prefetched: best candidate for upcoming slide
452 uno::Reference
<drawing::XDrawPage
> mxPrefetchSlide
;
453 /// save the XDrawPagesSupplier to retrieve polygons
454 uno::Reference
<drawing::XDrawPagesSupplier
> mxDrawPagesSupplier
;
455 /// Used by MediaFileManager, for media files with package url.
456 uno::Reference
<document::XStorageBasedDocument
> mxSBD
;
457 /// slide animation to be prefetched:
458 uno::Reference
<animations::XAnimationNode
> mxPrefetchAnimationNode
;
460 sal_Int16 mnCurrentCursor
;
462 sal_Int32 mnWaitSymbolRequestCount
;
463 bool mbAutomaticAdvancementMode
;
464 bool mbImageAnimationsAllowed
;
465 bool mbNoSlideTransitions
;
467 bool mbForceManualAdvance
;
469 bool mbSlideShowIdle
;
470 bool mbDisableAnimationZOrder
;
472 EffectRewinder maEffectRewinder
;
473 FrameSynchronization maFrameSynchronization
;
476 /** Separate event listener for animation, view and hyperlink events.
478 This handler is registered for slide animation end, view and
479 hyperlink events at the global EventMultiplexer, and forwards
480 notifications to the SlideShowImpl
482 struct SlideShowImpl::SeparateListenerImpl
: public EventHandler
,
483 public ViewRepaintHandler
,
484 public HyperlinkHandler
,
485 public AnimationEventHandler
487 SlideShowImpl
& mrShow
;
488 ScreenUpdater
& mrScreenUpdater
;
489 EventQueue
& mrEventQueue
;
491 SeparateListenerImpl( SlideShowImpl
& rShow
,
492 ScreenUpdater
& rScreenUpdater
,
493 EventQueue
& rEventQueue
) :
495 mrScreenUpdater( rScreenUpdater
),
496 mrEventQueue( rEventQueue
)
499 SeparateListenerImpl( const SeparateListenerImpl
& ) = delete;
500 SeparateListenerImpl
& operator=( const SeparateListenerImpl
& ) = delete;
503 virtual bool handleEvent() override
505 // DON't call notifySlideAnimationsEnded()
506 // directly, but queue an event. handleEvent()
507 // might be called from e.g.
508 // showNext(), and notifySlideAnimationsEnded() must not be called
509 // in recursion. Note that the event is scheduled for the next
510 // frame so that its expensive execution does not come in between
511 // sprite hiding and shape redraw (at the end of the animation of a
512 // shape), which would cause a flicker.
513 mrEventQueue
.addEventForNextRound(
514 makeEvent( [this] () { this->mrShow
.notifySlideAnimationsEnded(); },
515 "SlideShowImpl::notifySlideAnimationsEnded"));
519 // ViewRepaintHandler
520 virtual void viewClobbered( const UnoViewSharedPtr
& rView
) override
522 // given view needs repaint, request update
523 mrScreenUpdater
.notifyUpdate(rView
, true);
527 virtual bool handleHyperlink( OUString
const& rLink
) override
529 return mrShow
.notifyHyperLinkClicked(rLink
);
532 // AnimationEventHandler
533 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
) override
535 return mrShow
.handleAnimationEvent(rNode
);
539 SlideShowImpl::SlideShowImpl(
540 uno::Reference
<uno::XComponentContext
> const& xContext
)
541 : SlideShowImplBase(m_aMutex
),
543 maListenerContainer( m_aMutex
),
544 maShapeEventListeners(),
547 maUserPaintStrokeWidth(4.0),
548 mpPresTimer( std::make_shared
<canvas::tools::ElapsedTime
>() ),
549 maScreenUpdater(maViewContainer
),
550 maEventQueue( mpPresTimer
),
551 maEventMultiplexer( maEventQueue
,
553 maActivitiesQueue( mpPresTimer
),
554 maUserEventQueue( maEventMultiplexer
,
560 mpRehearseTimingsActivity(),
563 mpCurrentSlideTransitionSound(),
564 mxComponentContext( xContext
),
565 mxOptionalTransitionFactory(),
569 mxDrawPagesSupplier(),
571 mxPrefetchAnimationNode(),
572 mnCurrentCursor(awt::SystemPointer::ARROW
),
573 mnWaitSymbolRequestCount(0),
574 mbAutomaticAdvancementMode(false),
575 mbImageAnimationsAllowed( true ),
576 mbNoSlideTransitions( false ),
577 mbMouseVisible( true ),
578 mbForceManualAdvance( false ),
579 mbShowPaused( false ),
580 mbSlideShowIdle( true ),
581 mbDisableAnimationZOrder( false ),
582 maEffectRewinder(maEventMultiplexer
, maEventQueue
, maUserEventQueue
),
583 maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond
)
586 // keep care not constructing any UNO references to this inside ctor,
587 // shift that code to create()!
589 uno::Reference
<lang::XMultiComponentFactory
> xFactory(
590 mxComponentContext
->getServiceManager() );
596 // #i82460# try to retrieve special transition factory
597 mxOptionalTransitionFactory
.set(
598 xFactory
->createInstanceWithContext(
599 "com.sun.star.presentation.TransitionFactory",
600 mxComponentContext
),
603 catch (loader::CannotActivateFactoryException
const&)
608 mpListener
= std::make_shared
<SeparateListenerImpl
>(
612 maEventMultiplexer
.addSlideAnimationsEndHandler( mpListener
);
613 maEventMultiplexer
.addViewRepaintHandler( mpListener
);
614 maEventMultiplexer
.addHyperlinkHandler( mpListener
, 0.0 );
615 maEventMultiplexer
.addAnimationStartHandler( mpListener
);
616 maEventMultiplexer
.addAnimationEndHandler( mpListener
);
619 // we are about to be disposed (someone call dispose() on us)
620 void SlideShowImpl::disposing()
622 osl::MutexGuard
const guard( m_aMutex
);
624 maEffectRewinder
.dispose();
626 // stop slide transition sound, if any:
627 stopSlideTransitionSound();
629 mxComponentContext
.clear();
631 if( mpCurrentSlideTransitionSound
)
633 mpCurrentSlideTransitionSound
->dispose();
634 mpCurrentSlideTransitionSound
.reset();
637 mpWaitSymbol
.reset();
638 mpPointerSymbol
.reset();
640 if( mpRehearseTimingsActivity
)
642 mpRehearseTimingsActivity
->dispose();
643 mpRehearseTimingsActivity
.reset();
648 maEventMultiplexer
.removeSlideAnimationsEndHandler(mpListener
);
649 maEventMultiplexer
.removeViewRepaintHandler(mpListener
);
650 maEventMultiplexer
.removeHyperlinkHandler(mpListener
);
651 maEventMultiplexer
.removeAnimationStartHandler( mpListener
);
652 maEventMultiplexer
.removeAnimationEndHandler( mpListener
);
657 maUserEventQueue
.clear();
658 maActivitiesQueue
.clear();
659 maEventMultiplexer
.clear();
660 maEventQueue
.clear();
662 maShapeCursors
.clear();
663 maShapeEventListeners
.clear();
665 // send all listeners a disposing() that we are going down:
666 maListenerContainer
.disposeAndClear(
667 lang::EventObject( static_cast<cppu::OWeakObject
*>(this) ) );
669 maViewContainer
.dispose();
672 mxPrefetchAnimationNode
.clear();
673 mxPrefetchSlide
.clear();
674 mpPrefetchSlide
.reset();
675 mpCurrentSlide
.reset();
676 mpPreviousSlide
.reset();
679 uno::Sequence
< OUString
> SAL_CALL
SlideShowImpl::getSupportedServiceNames()
681 return { "com.sun.star.presentation.SlideShow" };
684 OUString SAL_CALL
SlideShowImpl::getImplementationName()
686 return "com.sun.star.comp.presentation.SlideShow";
689 sal_Bool SAL_CALL
SlideShowImpl::supportsService(const OUString
& aServiceName
)
691 return cppu::supportsService(this, aServiceName
);
694 /// stops the current slide transition sound
695 void SlideShowImpl::stopSlideTransitionSound()
697 if (mpCurrentSlideTransitionSound
)
699 mpCurrentSlideTransitionSound
->stopPlayback();
700 mpCurrentSlideTransitionSound
->dispose();
701 mpCurrentSlideTransitionSound
.reset();
705 SoundPlayerSharedPtr
SlideShowImpl::resetSlideTransitionSound( const uno::Any
& rSound
, bool bLoopSound
)
707 bool bStopSound
= false;
710 if( !(rSound
>>= bStopSound
) )
714 if( !bStopSound
&& url
.isEmpty() )
715 return SoundPlayerSharedPtr();
717 stopSlideTransitionSound();
723 mpCurrentSlideTransitionSound
= SoundPlayer::create(
724 maEventMultiplexer
, url
, mxComponentContext
, *this);
725 mpCurrentSlideTransitionSound
->setPlaybackLoop( bLoopSound
);
727 catch (lang::NoSupportException
const&)
729 // catch possible exceptions from SoundPlayer, since
730 // being not able to playback the sound is not a hard
731 // error here (still, the slide transition should be
735 return mpCurrentSlideTransitionSound
;
738 ActivitySharedPtr
SlideShowImpl::createSlideTransition(
739 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
740 const SlideSharedPtr
& rLeavingSlide
,
741 const SlideSharedPtr
& rEnteringSlide
,
742 const EventSharedPtr
& rTransitionEndEvent
)
744 ENSURE_OR_THROW( !maViewContainer
.empty(),
745 "createSlideTransition(): No views" );
746 ENSURE_OR_THROW( rEnteringSlide
,
747 "createSlideTransition(): No entering slide" );
749 // return empty transition, if slide transitions
751 if (mbNoSlideTransitions
)
752 return ActivitySharedPtr();
754 // retrieve slide change parameters from XDrawPage
755 uno::Reference
< beans::XPropertySet
> xPropSet( xDrawPage
,
760 SAL_INFO("slideshow", "createSlideTransition(): "
761 "Slide has no PropertySet - assuming no transition" );
762 return ActivitySharedPtr();
765 sal_Int16
nTransitionType(0);
766 if( !getPropertyValue( nTransitionType
,
770 SAL_INFO("slideshow", "createSlideTransition(): "
771 "Could not extract slide transition type from XDrawPage - assuming no transition" );
772 return ActivitySharedPtr();
775 sal_Int16
nTransitionSubType(0);
776 if( !getPropertyValue( nTransitionSubType
,
778 "TransitionSubtype") )
780 SAL_INFO("slideshow", "createSlideTransition(): "
781 "Could not extract slide transition subtype from XDrawPage - assuming no transition" );
782 return ActivitySharedPtr();
785 bool bTransitionDirection(false);
786 if( !getPropertyValue( bTransitionDirection
,
788 "TransitionDirection") )
790 SAL_INFO("slideshow", "createSlideTransition(): "
791 "Could not extract slide transition direction from XDrawPage - assuming default direction" );
794 sal_Int32
aUnoColor(0);
795 if( !getPropertyValue( aUnoColor
,
797 "TransitionFadeColor") )
799 SAL_INFO("slideshow", "createSlideTransition(): "
800 "Could not extract slide transition fade color from XDrawPage - assuming black" );
803 const RGBColor
aTransitionFadeColor( unoColor2RGBColor( aUnoColor
));
806 bool bLoopSound
= false;
808 if( !getPropertyValue( aSound
, xPropSet
, "Sound") )
809 SAL_INFO("slideshow", "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound" );
811 if( !getPropertyValue( bLoopSound
, xPropSet
, "LoopSound" ) )
812 SAL_INFO("slideshow", "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound" );
814 NumberAnimationSharedPtr
pTransition(
815 TransitionFactory::createSlideTransition(
821 mxOptionalTransitionFactory
,
824 bTransitionDirection
,
825 aTransitionFadeColor
,
826 resetSlideTransitionSound( aSound
, bLoopSound
) ));
829 return ActivitySharedPtr(); // no transition effect has been
830 // generated. Normally, that means
831 // that simply no transition is
832 // set on this slide.
834 double nTransitionDuration(0.0);
835 if( !getPropertyValue( nTransitionDuration
,
837 "TransitionDuration") )
839 SAL_INFO("slideshow", "createSlideTransition(): "
840 "Could not extract slide transition duration from XDrawPage - assuming no transition" );
841 return ActivitySharedPtr();
844 sal_Int32
nMinFrames(5);
845 if( !getPropertyValue( nMinFrames
,
847 "MinimalFrameNumber") )
849 SAL_INFO("slideshow", "createSlideTransition(): "
850 "No minimal number of frames given - assuming 5" );
853 // prefetch slide transition bitmaps, but postpone it after
854 // displaySlide() has finished - sometimes, view size has not yet
855 // reached final size
856 maEventQueue
.addEvent(
857 makeEvent( [pTransition
] () {
858 pTransition
->prefetch(); },
859 "Animation::prefetch"));
861 return ActivitySharedPtr(
862 ActivitiesFactory::createSimpleActivity(
863 ActivitiesFactory::CommonParameters(
870 std::optional
<double>(1.0),
874 basegfx::B2DSize( rEnteringSlide
->getSlideSize() ) ),
879 PolygonMap::iterator
SlideShowImpl::findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
)
881 // TODO(P2): optimize research in the map.
882 return maPolygons
.find(xDrawPage
);
885 SlideSharedPtr
SlideShowImpl::makeSlide(
886 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
887 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
888 uno::Reference
<animations::XAnimationNode
> const& xRootNode
)
890 if( !xDrawPage
.is() )
891 return SlideSharedPtr();
893 //Retrieve polygons for the current slide
894 PolygonMap::iterator aIter
= findPolygons(xDrawPage
);
896 const SlideSharedPtr
pSlide( createSlide(xDrawPage
,
908 maShapeEventListeners
,
910 (aIter
!= maPolygons
.end()) ? aIter
->second
: PolyPolygonVector(),
911 maUserPaintColor
? *maUserPaintColor
: RGBColor(),
912 maUserPaintStrokeWidth
,
914 mbImageAnimationsAllowed
,
915 mbDisableAnimationZOrder
) );
917 // prefetch show content (reducing latency for slide
918 // bitmap and effect start later on)
924 void SlideShowImpl::requestWaitSymbol()
926 ++mnWaitSymbolRequestCount
;
927 OSL_ASSERT(mnWaitSymbolRequestCount
>0);
929 if (mnWaitSymbolRequestCount
== 1)
933 // fall back to cursor
934 requestCursor(calcActiveCursor(mnCurrentCursor
));
937 mpWaitSymbol
->show();
941 void SlideShowImpl::releaseWaitSymbol()
943 --mnWaitSymbolRequestCount
;
944 OSL_ASSERT(mnWaitSymbolRequestCount
>=0);
946 if (mnWaitSymbolRequestCount
== 0)
950 // fall back to cursor
951 requestCursor(calcActiveCursor(mnCurrentCursor
));
954 mpWaitSymbol
->hide();
958 sal_Int16
SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape
) const
960 if( mnWaitSymbolRequestCount
>0 && !mpWaitSymbol
) // enforce wait cursor
961 nCursorShape
= awt::SystemPointer::WAIT
;
962 else if( !mbMouseVisible
) // enforce INVISIBLE
963 nCursorShape
= awt::SystemPointer::INVISIBLE
;
964 else if( maUserPaintColor
&&
965 nCursorShape
== awt::SystemPointer::ARROW
)
966 nCursorShape
= awt::SystemPointer::PEN
;
971 void SlideShowImpl::stopShow()
973 // Force-end running animation
974 // ===========================
977 mpCurrentSlide
->hide();
978 //Register polygons in the map
979 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
980 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
982 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
986 maEventQueue
.clear();
987 maActivitiesQueue
.clear();
989 // Attention: we MUST clear the user event queue here,
990 // this is because the current slide might have registered
991 // shape events (click or enter/leave), which might
992 // otherwise dangle forever in the queue (because of the
993 // shared ptr nature). If someone needs to change this:
994 // somehow unregister those shapes at the user event queue
995 // on notifySlideEnded().
996 maUserEventQueue
.clear();
998 // re-enable automatic effect advancement
999 // (maEventQueue.clear() above might have killed
1000 // maEventMultiplexer's tick events)
1001 if (mbAutomaticAdvancementMode
)
1003 // toggle automatic mode (enabling just again is
1004 // ignored by EventMultiplexer)
1005 maEventMultiplexer
.setAutomaticMode( false );
1006 maEventMultiplexer
.setAutomaticMode( true );
1010 class SlideShowImpl::PrefetchPropertiesFunc
1013 PrefetchPropertiesFunc( SlideShowImpl
* that_
,
1014 bool& rbSkipAllMainSequenceEffects
,
1015 bool& rbSkipSlideTransition
)
1016 : mpSlideShowImpl(that_
),
1017 mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects
),
1018 mrbSkipSlideTransition(rbSkipSlideTransition
)
1021 void operator()( beans::PropertyValue
const& rProperty
) const {
1022 if (rProperty
.Name
== "Prefetch" )
1024 uno::Sequence
<uno::Any
> seq
;
1025 if ((rProperty
.Value
>>= seq
) && seq
.getLength() == 2)
1027 seq
[0] >>= mpSlideShowImpl
->mxPrefetchSlide
;
1028 seq
[1] >>= mpSlideShowImpl
->mxPrefetchAnimationNode
;
1031 else if ( rProperty
.Name
== "SkipAllMainSequenceEffects" )
1033 rProperty
.Value
>>= mrbSkipAllMainSequenceEffects
;
1035 else if ( rProperty
.Name
== "SkipSlideTransition" )
1037 rProperty
.Value
>>= mrbSkipSlideTransition
;
1041 SAL_WARN( "slideshow", rProperty
.Name
);
1045 SlideShowImpl
*const mpSlideShowImpl
;
1046 bool& mrbSkipAllMainSequenceEffects
;
1047 bool& mrbSkipSlideTransition
;
1050 void SlideShowImpl::displaySlide(
1051 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
1052 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
1053 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
1054 uno::Sequence
<beans::PropertyValue
> const& rProperties
)
1056 osl::MutexGuard
const guard( m_aMutex
);
1061 maEffectRewinder
.setRootAnimationNode(xRootNode
);
1062 maEffectRewinder
.setCurrentSlide(xSlide
);
1064 // precondition: must only be called from the main thread!
1065 DBG_TESTSOLARMUTEX();
1067 mxDrawPagesSupplier
= xDrawPages
;
1068 mxSBD
= uno::Reference
<document::XStorageBasedDocument
>(mxDrawPagesSupplier
, uno::UNO_QUERY
);
1070 stopShow(); // MUST call that: results in
1071 // maUserEventQueue.clear(). What's more,
1072 // stopShow()'s currSlide->hide() call is
1073 // now also required, notifySlideEnded()
1075 // unconditionally. Otherwise, genuine
1076 // shape animations (drawing layer and
1077 // GIF) will not be stopped.
1079 bool bSkipAllMainSequenceEffects (false);
1080 bool bSkipSlideTransition (false);
1081 std::for_each( rProperties
.begin(),
1083 PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects
, bSkipSlideTransition
) );
1085 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1086 if (maViewContainer
.empty())
1089 // this here might take some time
1091 WaitSymbolLock
aLock (*this);
1093 mpPreviousSlide
= mpCurrentSlide
;
1094 mpCurrentSlide
.reset();
1096 if (matches( mpPrefetchSlide
, xSlide
, xRootNode
))
1098 // prefetched slide matches:
1099 mpCurrentSlide
= mpPrefetchSlide
;
1102 mpCurrentSlide
= makeSlide( xSlide
, xDrawPages
, xRootNode
);
1104 OSL_ASSERT( mpCurrentSlide
);
1107 basegfx::B2DSize oldSlideSize
;
1108 if( mpPreviousSlide
)
1109 oldSlideSize
= basegfx::B2DSize( mpPreviousSlide
->getSlideSize() );
1111 basegfx::B2DSize
const slideSize( mpCurrentSlide
->getSlideSize() );
1113 // push new transformation to all views, if size changed
1114 if( !mpPreviousSlide
|| oldSlideSize
!= slideSize
)
1116 for( const auto& pView
: maViewContainer
)
1117 pView
->setViewSize( slideSize
);
1119 // explicitly notify view change here,
1120 // because transformation might have changed:
1121 // optimization, this->notifyViewChange() would
1122 // repaint slide which is not necessary.
1123 maEventMultiplexer
.notifyViewsChanged();
1126 // create slide transition, and add proper end event
1127 // (which then starts the slide effects
1128 // via CURRENT_SLIDE.show())
1129 ActivitySharedPtr
pSlideChangeActivity (
1130 createSlideTransition(
1131 mpCurrentSlide
->getXDrawPage(),
1135 [this] () { this->notifySlideTransitionEnded(false); },
1136 "SlideShowImpl::notifySlideTransitionEnded")));
1138 if (bSkipSlideTransition
)
1140 // The transition activity was created for the side effects
1141 // (like sound transitions). Because we want to skip the
1142 // actual transition animation we do not need the activity
1144 pSlideChangeActivity
.reset();
1147 if (pSlideChangeActivity
)
1149 // factory generated a slide transition - activate it!
1150 maActivitiesQueue
.addActivity( pSlideChangeActivity
);
1154 // no transition effect on this slide - schedule slide
1155 // effect start event right away.
1156 maEventQueue
.addEvent(
1158 [this] () { this->notifySlideTransitionEnded(true); },
1159 "SlideShowImpl::notifySlideTransitionEnded"));
1164 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1165 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1167 xListener
->slideTransitionStarted();
1170 // We are currently rewinding an effect. This lead us from the next
1171 // slide to this one. To complete this we have to play back all main
1172 // sequence effects on this slide.
1173 if (bSkipAllMainSequenceEffects
)
1174 maEffectRewinder
.skipAllMainSequenceEffects();
1177 void SlideShowImpl::redisplayCurrentSlide()
1179 osl::MutexGuard
const guard( m_aMutex
);
1184 // precondition: must only be called from the main thread!
1185 DBG_TESTSOLARMUTEX();
1188 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1189 if (maViewContainer
.empty())
1192 // No transition effect on this slide - schedule slide
1193 // effect start event right away.
1194 maEventQueue
.addEvent(
1195 makeEvent( [this] () { this->notifySlideTransitionEnded(true); },
1196 "SlideShowImpl::notifySlideTransitionEnded"));
1198 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1199 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1201 xListener
->slideTransitionStarted();
1205 sal_Bool
SlideShowImpl::nextEffect()
1207 osl::MutexGuard
const guard( m_aMutex
);
1212 // precondition: must only be called from the main thread!
1213 DBG_TESTSOLARMUTEX();
1218 return maEventMultiplexer
.notifyNextEffect();
1221 sal_Bool
SlideShowImpl::previousEffect()
1223 osl::MutexGuard
const guard( m_aMutex
);
1228 // precondition: must only be called from the main thread!
1229 DBG_TESTSOLARMUTEX();
1235 return maEffectRewinder
.rewind(
1236 maScreenUpdater
.createLock(),
1237 [this]() { return this->redisplayCurrentSlide(); },
1238 [this]() { return this->rewindEffectToPreviousSlide(); } );
1242 void SlideShowImpl::rewindEffectToPreviousSlide()
1244 // Show the wait symbol now and prevent it from showing temporary slide
1245 // content while effects are played back.
1246 WaitSymbolLock
aLock (*this);
1248 // A previous call to EffectRewinder::Rewind could not rewind the current
1249 // effect because there are no effects on the current slide or none has
1250 // yet been displayed. Go to the previous slide.
1251 notifySlideEnded(true);
1253 // Process pending events once more in order to have the following
1254 // screen update show the last effect. Not sure whether this should be
1256 maEventQueue
.forceEmpty();
1258 // We have to call the screen updater before the wait symbol is turned
1259 // off. Otherwise the wait symbol would force the display of an
1260 // intermediate state of the slide (before the effects are replayed.)
1261 maScreenUpdater
.commitUpdates();
1264 sal_Bool
SlideShowImpl::startShapeActivity(
1265 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1267 osl::MutexGuard
const guard( m_aMutex
);
1269 // precondition: must only be called from the main thread!
1270 DBG_TESTSOLARMUTEX();
1273 OSL_FAIL( "not yet implemented!" );
1277 sal_Bool
SlideShowImpl::stopShapeActivity(
1278 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1280 osl::MutexGuard
const guard( m_aMutex
);
1282 // precondition: must only be called from the main thread!
1283 DBG_TESTSOLARMUTEX();
1286 OSL_FAIL( "not yet implemented!" );
1290 sal_Bool
SlideShowImpl::pause( sal_Bool bPauseShow
)
1292 osl::MutexGuard
const guard( m_aMutex
);
1297 // precondition: must only be called from the main thread!
1298 DBG_TESTSOLARMUTEX();
1301 mpPresTimer
->pauseTimer();
1303 mpPresTimer
->continueTimer();
1305 maEventMultiplexer
.notifyPauseMode(bPauseShow
);
1307 mbShowPaused
= bPauseShow
;
1311 uno::Reference
<drawing::XDrawPage
> SlideShowImpl::getCurrentSlide()
1313 osl::MutexGuard
const guard( m_aMutex
);
1316 return uno::Reference
<drawing::XDrawPage
>();
1318 // precondition: must only be called from the main thread!
1319 DBG_TESTSOLARMUTEX();
1322 return mpCurrentSlide
->getXDrawPage();
1324 return uno::Reference
<drawing::XDrawPage
>();
1327 sal_Bool
SlideShowImpl::addView(
1328 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1330 osl::MutexGuard
const guard( m_aMutex
);
1335 // precondition: must only be called from the main thread!
1336 DBG_TESTSOLARMUTEX();
1338 // first of all, check if view has a valid canvas
1339 ENSURE_OR_RETURN_FALSE( xView
.is(), "addView(): Invalid view" );
1340 ENSURE_OR_RETURN_FALSE( xView
->getCanvas().is(),
1341 "addView(): View does not provide a valid canvas" );
1343 UnoViewSharedPtr
const pView( createSlideView(
1346 maEventMultiplexer
));
1347 if (!maViewContainer
.addView( pView
))
1348 return false; // view already added
1350 // initialize view content
1351 // =======================
1355 // set view transformation
1356 const basegfx::B2ISize slideSize
= mpCurrentSlide
->getSlideSize();
1357 pView
->setViewSize( basegfx::B2DSize( slideSize
.getX(),
1358 slideSize
.getY() ) );
1361 // clear view area (since it's newly added,
1362 // we need a clean slate)
1365 // broadcast newly added view
1366 maEventMultiplexer
.notifyViewAdded( pView
);
1368 // set current mouse ptr
1369 pView
->setCursorShape( calcActiveCursor(mnCurrentCursor
) );
1374 sal_Bool
SlideShowImpl::removeView(
1375 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1377 osl::MutexGuard
const guard( m_aMutex
);
1379 // precondition: must only be called from the main thread!
1380 DBG_TESTSOLARMUTEX();
1382 ENSURE_OR_RETURN_FALSE( xView
.is(), "removeView(): Invalid view" );
1384 UnoViewSharedPtr
const pView( maViewContainer
.removeView( xView
) );
1386 return false; // view was not added in the first place
1388 // remove view from EventMultiplexer (mouse events etc.)
1389 maEventMultiplexer
.notifyViewRemoved( pView
);
1396 void SlideShowImpl::registerUserPaintPolygons( const uno::Reference
< lang::XMultiServiceFactory
>& xDocFactory
)
1398 //Retrieve Polygons if user ends presentation by context menu
1401 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
1402 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
1404 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
1407 //Creating the layer for shapes drawn during slideshow
1408 // query for the XLayerManager
1409 uno::Reference
< drawing::XLayerSupplier
> xLayerSupplier(xDocFactory
, uno::UNO_QUERY
);
1410 uno::Reference
< container::XNameAccess
> xNameAccess
= xLayerSupplier
->getLayerManager();
1411 uno::Reference
< drawing::XLayerManager
> xLayerManager(xNameAccess
, uno::UNO_QUERY
);
1414 uno::Reference
< drawing::XLayer
> xDrawnInSlideshow
;
1415 uno::Any aPropLayer
;
1416 OUString sLayerName
= "DrawnInSlideshow";
1417 if (xNameAccess
->hasByName(sLayerName
))
1419 xNameAccess
->getByName(sLayerName
) >>= xDrawnInSlideshow
;
1423 xDrawnInSlideshow
= xLayerManager
->insertNewByIndex(xLayerManager
->getCount());
1424 aPropLayer
<<= sLayerName
;
1425 xDrawnInSlideshow
->setPropertyValue("Name", aPropLayer
);
1428 // ODF defaults from ctor of SdrLayer are not automatically set on the here
1429 // created XLayer. Need to be done explicitly here.
1430 aPropLayer
<<= true;
1431 xDrawnInSlideshow
->setPropertyValue("IsVisible", aPropLayer
);
1432 xDrawnInSlideshow
->setPropertyValue("IsPrintable", aPropLayer
);
1433 aPropLayer
<<= false;
1434 xDrawnInSlideshow
->setPropertyValue("IsLocked", aPropLayer
);
1436 //Register polygons for each slide
1437 for( const auto& rPoly
: maPolygons
)
1439 PolyPolygonVector aPolygons
= rPoly
.second
;
1440 //Get shapes for the slide
1441 css::uno::Reference
< css::drawing::XShapes
> Shapes
= rPoly
.first
;
1442 //Retrieve polygons for one slide
1443 for( const auto& pPolyPoly
: aPolygons
)
1445 ::basegfx::B2DPolyPolygon b2DPolyPoly
= ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly
->getUNOPolyPolygon());
1447 //Normally there is only one polygon
1448 for(sal_uInt32 i
=0; i
< b2DPolyPoly
.count();i
++)
1450 const ::basegfx::B2DPolygon
& aPoly
= b2DPolyPoly
.getB2DPolygon(i
);
1451 sal_uInt32 nPoints
= aPoly
.count();
1455 //create the PolyLineShape
1456 uno::Reference
< uno::XInterface
> polyshape(xDocFactory
->createInstance(
1457 "com.sun.star.drawing.PolyLineShape" ) );
1458 uno::Reference
< drawing::XShape
> rPolyShape(polyshape
, uno::UNO_QUERY
);
1460 //Add the shape to the slide
1461 Shapes
->add(rPolyShape
);
1463 //Retrieve shape properties
1464 uno::Reference
< beans::XPropertySet
> aXPropSet( rPolyShape
, uno::UNO_QUERY
);
1465 //Construct a sequence of points sequence
1466 drawing::PointSequenceSequence aRetval
;
1467 //Create only one sequence for one polygon
1468 aRetval
.realloc( 1 );
1469 // Retrieve the sequence of points from aRetval
1470 drawing::PointSequence
* pOuterSequence
= aRetval
.getArray();
1471 // Create 2 points in this sequence
1472 pOuterSequence
->realloc(nPoints
);
1473 // Get these points which are in an array
1474 awt::Point
* pInnerSequence
= pOuterSequence
->getArray();
1475 for( sal_uInt32 n
= 0; n
< nPoints
; n
++ )
1477 //Create a point from the polygon
1478 *pInnerSequence
++ = awt::Point(
1479 basegfx::fround(aPoly
.getB2DPoint(n
).getX()),
1480 basegfx::fround(aPoly
.getB2DPoint(n
).getY()));
1483 //Fill the properties
1484 //Give the built PointSequenceSequence.
1487 aXPropSet
->setPropertyValue("PolyPolygon", aParam
);
1489 //LineStyle : SOLID by default
1490 drawing::LineStyle eLS
;
1491 eLS
= drawing::LineStyle_SOLID
;
1492 aXPropSet
->setPropertyValue("LineStyle", uno::Any(eLS
) );
1495 sal_uInt32 nLineColor
;
1496 nLineColor
= pPolyPoly
->getRGBALineColor();
1497 //Transform polygon color from RRGGBBAA to AARRGGBB
1498 aXPropSet
->setPropertyValue("LineColor", uno::Any(RGBAColor2UnoColor(nLineColor
)) );
1502 fLineWidth
= pPolyPoly
->getStrokeWidth();
1503 aXPropSet
->setPropertyValue("LineWidth", uno::Any(static_cast<sal_Int32
>(fLineWidth
)) );
1505 // make polygons special
1506 xLayerManager
->attachShapeToLayer(rPolyShape
, xDrawnInSlideshow
);
1513 sal_Bool
SlideShowImpl::setProperty( beans::PropertyValue
const& rProperty
)
1515 osl::MutexGuard
const guard( m_aMutex
);
1520 // precondition: must only be called from the main thread!
1521 DBG_TESTSOLARMUTEX();
1523 if ( rProperty
.Name
== "AutomaticAdvancement" )
1525 double nTimeout(0.0);
1526 mbAutomaticAdvancementMode
= (rProperty
.Value
>>= nTimeout
);
1527 if (mbAutomaticAdvancementMode
)
1529 maEventMultiplexer
.setAutomaticTimeout( nTimeout
);
1531 maEventMultiplexer
.setAutomaticMode( mbAutomaticAdvancementMode
);
1535 if ( rProperty
.Name
== "UserPaintColor" )
1537 sal_Int32
nColor(0);
1538 if (rProperty
.Value
>>= nColor
)
1540 OSL_ENSURE( mbMouseVisible
,
1541 "setProperty(): User paint overrides invisible mouse" );
1543 // enable user paint
1544 maUserPaintColor
= unoColor2RGBColor(nColor
);
1545 if( mpCurrentSlide
&& !mpCurrentSlide
->isPaintOverlayActive() )
1546 mpCurrentSlide
->enablePaintOverlay();
1548 maEventMultiplexer
.notifyUserPaintColor( *maUserPaintColor
);
1552 // disable user paint
1553 maUserPaintColor
.reset();
1554 maEventMultiplexer
.notifyUserPaintDisabled();
1562 //adding support for erasing features in UserPaintOverlay
1563 if ( rProperty
.Name
== "EraseAllInk" )
1565 bool bEraseAllInk(false);
1566 if (rProperty
.Value
>>= bEraseAllInk
)
1568 OSL_ENSURE( mbMouseVisible
,
1569 "setProperty(): User paint overrides invisible mouse" );
1571 // enable user paint
1572 maEraseAllInk
= bEraseAllInk
;
1573 maEventMultiplexer
.notifyEraseAllInk( *maEraseAllInk
);
1579 if ( rProperty
.Name
== "SwitchPenMode" )
1581 bool bSwitchPenMode(false);
1582 if (rProperty
.Value
>>= bSwitchPenMode
)
1584 OSL_ENSURE( mbMouseVisible
,
1585 "setProperty(): User paint overrides invisible mouse" );
1588 // Switch to Pen Mode
1589 maEventMultiplexer
.notifySwitchPenMode();
1595 if ( rProperty
.Name
== "SwitchEraserMode" )
1597 bool bSwitchEraserMode(false);
1598 if (rProperty
.Value
>>= bSwitchEraserMode
)
1600 OSL_ENSURE( mbMouseVisible
,
1601 "setProperty(): User paint overrides invisible mouse" );
1602 if(bSwitchEraserMode
){
1603 // switch to Eraser mode
1604 maEventMultiplexer
.notifySwitchEraserMode();
1611 if ( rProperty
.Name
== "EraseInk" )
1613 sal_Int32
nEraseInk(100);
1614 if (rProperty
.Value
>>= nEraseInk
)
1616 OSL_ENSURE( mbMouseVisible
,
1617 "setProperty(): User paint overrides invisible mouse" );
1619 // enable user paint
1620 maEraseInk
= nEraseInk
;
1621 maEventMultiplexer
.notifyEraseInkWidth( *maEraseInk
);
1627 // new Property for pen's width
1628 if ( rProperty
.Name
== "UserPaintStrokeWidth" )
1631 if (rProperty
.Value
>>= nWidth
)
1633 OSL_ENSURE( mbMouseVisible
,"setProperty(): User paint overrides invisible mouse" );
1634 // enable user paint stroke width
1635 maUserPaintStrokeWidth
= nWidth
;
1636 maEventMultiplexer
.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth
);
1642 if ( rProperty
.Name
== "AdvanceOnClick" )
1644 bool bAdvanceOnClick
= false;
1645 if (! (rProperty
.Value
>>= bAdvanceOnClick
))
1647 maUserEventQueue
.setAdvanceOnClick( bAdvanceOnClick
);
1651 if ( rProperty
.Name
== "DisableAnimationZOrder" )
1653 bool bDisableAnimationZOrder
= false;
1654 if (! (rProperty
.Value
>>= bDisableAnimationZOrder
))
1656 mbDisableAnimationZOrder
= bDisableAnimationZOrder
;
1660 if ( rProperty
.Name
== "ImageAnimationsAllowed" )
1662 if (! (rProperty
.Value
>>= mbImageAnimationsAllowed
))
1665 // TODO(F3): Forward to slides!
1669 if ( rProperty
.Name
== "MouseVisible" )
1671 if (! (rProperty
.Value
>>= mbMouseVisible
))
1674 requestCursor(mnCurrentCursor
);
1679 if ( rProperty
.Name
== "ForceManualAdvance" )
1681 return (rProperty
.Value
>>= mbForceManualAdvance
);
1684 if ( rProperty
.Name
== "RehearseTimings" )
1686 bool bRehearseTimings
= false;
1687 if (! (rProperty
.Value
>>= bRehearseTimings
))
1690 if (bRehearseTimings
)
1692 // TODO(Q3): Move to slide
1693 mpRehearseTimingsActivity
= RehearseTimingsActivity::create(
1705 mpBox2DDummyPtr
) );
1707 else if (mpRehearseTimingsActivity
)
1709 // removes timer from all views:
1710 mpRehearseTimingsActivity
->dispose();
1711 mpRehearseTimingsActivity
.reset();
1716 if ( rProperty
.Name
== "WaitSymbolBitmap" )
1718 uno::Reference
<rendering::XBitmap
> xBitmap
;
1719 if (! (rProperty
.Value
>>= xBitmap
))
1722 mpWaitSymbol
= WaitSymbol::create( xBitmap
,
1730 if ( rProperty
.Name
== "PointerSymbolBitmap" )
1732 uno::Reference
<rendering::XBitmap
> xBitmap
;
1733 if (! (rProperty
.Value
>>= xBitmap
))
1736 mpPointerSymbol
= PointerSymbol::create( xBitmap
,
1744 if ( rProperty
.Name
== "PointerVisible" )
1747 if (!(rProperty
.Value
>>= visible
))
1750 mpPointerSymbol
->setVisible(visible
);
1754 if ( rProperty
.Name
== "PointerPosition")
1756 css::geometry::RealPoint2D pos
;
1757 if (! (rProperty
.Value
>>= pos
))
1760 mpPointerSymbol
->viewsChanged(pos
);
1764 if (rProperty
.Name
== "NoSlideTransitions" )
1766 return (rProperty
.Value
>>= mbNoSlideTransitions
);
1769 if ( rProperty
.Name
== "IsSoundEnabled" )
1771 uno::Sequence
<uno::Any
> aValues
;
1772 uno::Reference
<presentation::XSlideShowView
> xView
;
1773 bool bValue (false);
1774 if ((rProperty
.Value
>>= aValues
)
1775 && aValues
.getLength()==2
1776 && (aValues
[0] >>= xView
)
1777 && (aValues
[1] >>= bValue
))
1779 // Look up the view.
1780 auto iView
= std::find_if(maViewContainer
.begin(), maViewContainer
.end(),
1781 [&xView
](const UnoViewSharedPtr
& rxView
) { return rxView
&& rxView
->getUnoView() == xView
; });
1782 if (iView
!= maViewContainer
.end())
1784 // Store the flag at the view so that media shapes have
1786 (*iView
)->setIsSoundEnabled(bValue
);
1795 void SlideShowImpl::addSlideShowListener(
1796 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1798 osl::MutexGuard
const guard( m_aMutex
);
1803 // container syncs with passed mutex ref
1804 maListenerContainer
.addInterface(xListener
);
1807 void SlideShowImpl::removeSlideShowListener(
1808 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1810 osl::MutexGuard
const guard( m_aMutex
);
1812 // container syncs with passed mutex ref
1813 maListenerContainer
.removeInterface(xListener
);
1816 void SlideShowImpl::addShapeEventListener(
1817 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1818 uno::Reference
<drawing::XShape
> const& xShape
)
1820 osl::MutexGuard
const guard( m_aMutex
);
1825 // precondition: must only be called from the main thread!
1826 DBG_TESTSOLARMUTEX();
1828 ShapeEventListenerMap::iterator aIter
;
1829 if( (aIter
=maShapeEventListeners
.find( xShape
)) ==
1830 maShapeEventListeners
.end() )
1832 // no entry for this shape -> create one
1833 aIter
= maShapeEventListeners
.emplace(
1835 std::make_shared
<comphelper::OInterfaceContainerHelper2
>(
1839 // add new listener to broadcaster
1841 aIter
->second
->addInterface( xListener
);
1843 maEventMultiplexer
.notifyShapeListenerAdded(xShape
);
1846 void SlideShowImpl::removeShapeEventListener(
1847 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1848 uno::Reference
<drawing::XShape
> const& xShape
)
1850 osl::MutexGuard
const guard( m_aMutex
);
1852 // precondition: must only be called from the main thread!
1853 DBG_TESTSOLARMUTEX();
1855 ShapeEventListenerMap::iterator aIter
;
1856 if( (aIter
= maShapeEventListeners
.find( xShape
)) !=
1857 maShapeEventListeners
.end() )
1859 // entry for this shape found -> remove listener from
1863 "SlideShowImpl::removeShapeEventListener(): "
1864 "listener map contains NULL broadcast helper" );
1866 aIter
->second
->removeInterface( xListener
);
1869 maEventMultiplexer
.notifyShapeListenerRemoved(xShape
);
1872 void SlideShowImpl::setShapeCursor(
1873 uno::Reference
<drawing::XShape
> const& xShape
, sal_Int16 nPointerShape
)
1875 osl::MutexGuard
const guard( m_aMutex
);
1880 // precondition: must only be called from the main thread!
1881 DBG_TESTSOLARMUTEX();
1883 ShapeCursorMap::iterator aIter
;
1884 if( (aIter
=maShapeCursors
.find( xShape
)) == maShapeCursors
.end() )
1886 // no entry for this shape -> create one
1887 if( nPointerShape
!= awt::SystemPointer::ARROW
)
1889 // add new entry, unless shape shall display
1890 // normal pointer arrow -> no need to handle that
1892 maShapeCursors
.emplace(xShape
, nPointerShape
);
1895 else if( nPointerShape
== awt::SystemPointer::ARROW
)
1897 // shape shall display normal cursor -> can disable
1898 // the cursor and clear the entry
1899 maShapeCursors
.erase( xShape
);
1903 // existing entry found, update with new cursor ID
1904 aIter
->second
= nPointerShape
;
1908 bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape
)
1910 mnCurrentCursor
= nCursorShape
;
1912 const sal_Int16 nActualCursor
= calcActiveCursor(mnCurrentCursor
);
1914 // change all views to the requested cursor ID
1915 for( const auto& pView
: maViewContainer
)
1916 pView
->setCursorShape( nActualCursor
);
1918 return nActualCursor
==nCursorShape
;
1921 void SlideShowImpl::resetCursor()
1923 mnCurrentCursor
= awt::SystemPointer::ARROW
;
1925 const sal_Int16 nActualCursor
= calcActiveCursor( mnCurrentCursor
);
1926 // change all views to the default cursor ID
1927 for( const auto& pView
: maViewContainer
)
1928 pView
->setCursorShape( nActualCursor
);
1931 sal_Bool
SlideShowImpl::update( double & nNextTimeout
)
1933 osl::MutexGuard
const guard( m_aMutex
);
1938 // precondition: update() must only be called from the
1940 DBG_TESTSOLARMUTEX();
1944 // commit frame (might be repaints pending)
1945 maScreenUpdater
.commitUpdates();
1951 // TODO(F2): re-evaluate whether that timer lagging makes
1954 // hold timer, while processing the queues:
1955 // 1. when there is more than one active activity this ensures the
1956 // same time for all activities and events
1957 // 2. processing of events may lead to creation of further events
1958 // that have zero delay. While the timer is stopped these events
1959 // are processed in the same run.
1961 //Get a shared-ptr that outlives the scope-guard which will
1962 //ensure that the pointed-to-item exists in the case of a
1963 //::dispose clearing mpPresTimer
1964 std::shared_ptr
<canvas::tools::ElapsedTime
> xTimer(mpPresTimer
);
1965 comphelper::ScopeGuard
scopeGuard(
1966 [&xTimer
]() { return xTimer
->releaseTimer(); } );
1967 xTimer
->holdTimer();
1970 maEventQueue
.process();
1972 // #i118671# the call above may execute a macro bound to an object. In
1973 // that case this macro may have destroyed this local slideshow so that it
1974 // is disposed (see bugdoc at task). In that case, detect this and exit
1975 // gently from this slideshow. Do not forget to disable the scoped
1976 // call to mpPresTimer, this will be deleted if we are disposed.
1979 scopeGuard
.dismiss();
1983 maActivitiesQueue
.process();
1985 // commit frame to screen
1986 maFrameSynchronization
.Synchronize();
1987 maScreenUpdater
.commitUpdates();
1989 // TODO(Q3): remove need to call dequeued() from
1990 // activities. feels like a wart.
1992 // Rationale for ActivitiesQueue::processDequeued(): when
1993 // an activity ends, it usually pushed the end state to
1994 // the animated shape in question, and ends the animation
1995 // (which, in turn, will usually disable shape sprite
1996 // mode). Disabling shape sprite mode causes shape
1997 // repaint, which, depending on slide content, takes
1998 // considerably more time than sprite updates. Thus, the
1999 // last animation step tends to look delayed. To
2000 // camouflage this, reaching end position and disabling
2001 // sprite mode is split into two (normal Activity::end(),
2002 // and Activity::dequeued()). Now, the reason to call
2003 // commitUpdates() twice here is caused by the unrelated
2004 // fact that during wait cursor display/hide, the screen
2005 // is updated, and shows hidden sprites, but, in case of
2006 // leaving the second commitUpdates() call out and punting
2007 // that to the next round, no updated static slide
2008 // content. In short, the last shape animation of a slide
2009 // tends to blink at its end.
2011 // process dequeued activities _after_ commit to screen
2012 maActivitiesQueue
.processDequeued();
2014 // commit frame to screen
2015 maScreenUpdater
.commitUpdates();
2017 // Time held until here
2019 const bool bActivitiesLeft
= ! maActivitiesQueue
.isEmpty();
2020 const bool bTimerEventsLeft
= ! maEventQueue
.isEmpty();
2021 const bool bRet
= (bActivitiesLeft
|| bTimerEventsLeft
);
2025 // calc nNextTimeout value:
2026 if (bActivitiesLeft
)
2028 // Activity queue is not empty. Tell caller that we would
2029 // like to render another frame.
2031 // Return a zero time-out to signal our caller to call us
2032 // back as soon as possible. The actual timing, waiting the
2033 // appropriate amount of time between frames, is then done
2034 // by the maFrameSynchronization object.
2036 maFrameSynchronization
.Activate();
2040 // timer events left:
2041 // difference from current time (nota bene:
2042 // time no longer held here!) to the next event in
2045 // #i61190# Retrieve next timeout only _after_
2046 // processing activity queue
2048 // ensure positive value:
2049 nNextTimeout
= std::max( 0.0, maEventQueue
.nextTimeout() );
2051 // There is no active animation so the frame rate does not
2052 // need to be synchronized.
2053 maFrameSynchronization
.Deactivate();
2056 mbSlideShowIdle
= false;
2059 #if defined(DBG_UTIL)
2060 // when slideshow is idle, issue an XUpdatable::update() call
2061 // exactly once after a previous animation sequence finished -
2062 // this might trigger screen dumps on some canvas
2064 if( !mbSlideShowIdle
&&
2066 nNextTimeout
> 1.0) )
2068 for( const auto& pView
: maViewContainer
)
2072 uno::Reference
< presentation::XSlideShowView
> xView( pView
->getUnoView(),
2073 uno::UNO_SET_THROW
);
2074 uno::Reference
<util::XUpdatable
> const xUpdatable(
2075 xView
->getCanvas(), uno::UNO_QUERY
);
2076 if (xUpdatable
.is()) // not supported in PresenterCanvas
2078 xUpdatable
->update();
2081 catch( uno::RuntimeException
& )
2085 catch( uno::Exception
& )
2087 TOOLS_WARN_EXCEPTION( "slideshow", "" );
2091 mbSlideShowIdle
= true;
2099 void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide
)
2101 osl::MutexGuard
const guard( m_aMutex
);
2103 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2104 OSL_ENSURE( mpCurrentSlide
,
2105 "notifySlideTransitionEnded(): Invalid current slide" );
2108 mpCurrentSlide
->update_settings( !!maUserPaintColor
, maUserPaintColor
? *maUserPaintColor
: RGBColor(), maUserPaintStrokeWidth
);
2110 // first init show, to give the animations
2111 // the chance to register SlideStartEvents
2112 const bool bBackgroundLayerRendered( !bPaintSlide
);
2113 mpCurrentSlide
->show( bBackgroundLayerRendered
);
2114 maEventMultiplexer
.notifySlideStartEvent();
2118 void queryAutomaticSlideTransition( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
2119 double& nAutomaticNextSlideTimeout
,
2120 bool& bHasAutomaticNextSlide
)
2122 // retrieve slide change parameters from XDrawPage
2123 // ===============================================
2125 uno::Reference
< beans::XPropertySet
> xPropSet( xDrawPage
,
2128 sal_Int32
nChange(0);
2129 if( !xPropSet
.is() ||
2130 !getPropertyValue( nChange
,
2134 SAL_INFO("slideshow",
2135 "queryAutomaticSlideTransition(): "
2136 "Could not extract slide change mode from XDrawPage - assuming <none>" );
2139 bHasAutomaticNextSlide
= nChange
== 1;
2141 if( !xPropSet
.is() ||
2142 !getPropertyValue( nAutomaticNextSlideTimeout
,
2144 "HighResDuration") )
2146 SAL_INFO("slideshow",
2147 "queryAutomaticSlideTransition(): "
2148 "Could not extract slide transition timeout from "
2149 "XDrawPage - assuming 1 sec" );
2153 void SlideShowImpl::notifySlideAnimationsEnded()
2155 osl::MutexGuard
const guard( m_aMutex
);
2157 //Draw polygons above animations
2158 mpCurrentSlide
->drawPolygons();
2160 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2162 // This struct will receive the (interruptable) event,
2163 // that triggers the notifySlideEnded() method.
2164 InterruptableEventPair aNotificationEvents
;
2166 if( maEventMultiplexer
.getAutomaticMode() )
2168 OSL_ENSURE( ! mpRehearseTimingsActivity
,
2169 "unexpected: RehearseTimings mode!" );
2171 // schedule a slide end event, with automatic mode's
2173 aNotificationEvents
= makeInterruptableDelay(
2174 [this]() { return this->notifySlideEnded( false ); },
2175 maEventMultiplexer
.getAutomaticTimeout() );
2179 OSL_ENSURE( mpCurrentSlide
,
2180 "notifySlideAnimationsEnded(): Invalid current slide!" );
2182 bool bHasAutomaticNextSlide
=false;
2183 double nAutomaticNextSlideTimeout
=0.0;
2184 queryAutomaticSlideTransition(mpCurrentSlide
->getXDrawPage(),
2185 nAutomaticNextSlideTimeout
,
2186 bHasAutomaticNextSlide
);
2188 // check whether slide transition should happen
2189 // 'automatically'. If yes, simply schedule the
2190 // specified timeout.
2191 // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2192 // override any individual slide setting, to always
2193 // step slides manually.
2194 if( !mbForceManualAdvance
&&
2195 !mpRehearseTimingsActivity
&&
2196 bHasAutomaticNextSlide
)
2198 aNotificationEvents
= makeInterruptableDelay(
2199 [this]() { return this->notifySlideEnded( false ); },
2200 nAutomaticNextSlideTimeout
);
2202 // TODO(F2): Provide a mechanism to let the user override
2203 // this automatic timeout via next()
2207 if (mpRehearseTimingsActivity
)
2208 mpRehearseTimingsActivity
->start();
2210 // generate click event. Thus, the user must
2211 // trigger the actual end of a slide. No need to
2212 // generate interruptable event here, there's no
2213 // timeout involved.
2214 aNotificationEvents
.mpImmediateEvent
=
2215 makeEvent( [this] () { this->notifySlideEnded(false); },
2216 "SlideShowImpl::notifySlideEnded");
2220 // register events on the queues. To make automatic slide
2221 // changes interruptable, register the interruption event
2222 // as a nextEffectEvent target. Note that the timeout
2223 // event is optional (e.g. manual slide changes don't
2224 // generate a timeout)
2225 maUserEventQueue
.registerNextEffectEvent(
2226 aNotificationEvents
.mpImmediateEvent
);
2228 if( aNotificationEvents
.mpTimeoutEvent
)
2229 maEventQueue
.addEvent( aNotificationEvents
.mpTimeoutEvent
);
2231 // current slide's main sequence is over. Now should be
2232 // the time to prefetch the next slide (if any), and
2233 // prepare the initial slide bitmap (speeds up slide
2234 // change setup time a lot). Show the wait cursor, this
2235 // indeed might take some seconds.
2237 WaitSymbolLock
aLock (*this);
2239 if (! matches( mpPrefetchSlide
,
2240 mxPrefetchSlide
, mxPrefetchAnimationNode
))
2242 mpPrefetchSlide
= makeSlide( mxPrefetchSlide
, mxDrawPagesSupplier
,
2243 mxPrefetchAnimationNode
);
2245 if (mpPrefetchSlide
)
2247 // ignore return value, this is just to populate
2248 // Slide's internal bitmap buffer, such that the time
2249 // needed to generate the slide bitmap is not spent
2250 // when the slide change is requested.
2251 mpPrefetchSlide
->getCurrentSlideBitmap( *maViewContainer
.begin() );
2255 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2256 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
2258 xListener
->slideAnimationsEnded();
2262 void SlideShowImpl::notifySlideEnded (const bool bReverse
)
2264 osl::MutexGuard
const guard( m_aMutex
);
2266 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2268 if (mpRehearseTimingsActivity
&& !bReverse
)
2270 const double time
= mpRehearseTimingsActivity
->stop();
2271 if (mpRehearseTimingsActivity
->hasBeenClicked())
2273 // save time at current drawpage:
2274 uno::Reference
<beans::XPropertySet
> xPropSet(
2275 mpCurrentSlide
->getXDrawPage(), uno::UNO_QUERY
);
2276 OSL_ASSERT( xPropSet
.is() );
2279 xPropSet
->setPropertyValue(
2281 uno::Any( static_cast<sal_Int32
>(1) ) );
2282 xPropSet
->setPropertyValue(
2284 uno::Any( static_cast<sal_Int32
>(time
) ) );
2290 maEventMultiplexer
.notifySlideEndEvent();
2292 stopShow(); // MUST call that: results in
2293 // maUserEventQueue.clear(). What's more,
2294 // stopShow()'s currSlide->hide() call is
2295 // now also required, notifySlideEnded()
2297 // unconditionally. Otherwise, genuine
2298 // shape animations (drawing layer and
2299 // GIF) will not be stopped.
2301 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2302 [&bReverse
]( const uno::Reference
< presentation::XSlideShowListener
>& xListener
)
2303 { return xListener
->slideEnded( bReverse
); } );
2306 bool SlideShowImpl::notifyHyperLinkClicked( OUString
const& hyperLink
)
2308 osl::MutexGuard
const guard( m_aMutex
);
2310 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2311 [&hyperLink
]( const uno::Reference
< presentation::XSlideShowListener
>& xListener
)
2312 { return xListener
->hyperLinkClicked( hyperLink
); } );
2316 /** Notification from eventmultiplexer that an animation event has occurred.
2317 This will be forwarded to all registered XSlideShoeListener
2319 bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
)
2321 osl::MutexGuard
const guard( m_aMutex
);
2323 uno::Reference
<animations::XAnimationNode
> xNode( rNode
->getXAnimationNode() );
2325 switch( rNode
->getState() )
2327 case AnimationNode::ACTIVE
:
2328 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2329 [&xNode
]( const uno::Reference
< animations::XAnimationListener
>& xListener
)
2330 { return xListener
->beginEvent( xNode
); } );
2333 case AnimationNode::FROZEN
:
2334 case AnimationNode::ENDED
:
2335 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2336 [&xNode
]( const uno::Reference
< animations::XAnimationListener
>& xListener
)
2337 { return xListener
->endEvent( xNode
); } );
2338 if(mpCurrentSlide
->isPaintOverlayActive())
2339 mpCurrentSlide
->drawPolygons();
2348 std::shared_ptr
<avmedia::MediaTempFile
> SlideShowImpl::getMediaTempFile(const OUString
& aUrl
)
2350 std::shared_ptr
<avmedia::MediaTempFile
> aRet
;
2355 comphelper::LifecycleProxy aProxy
;
2356 uno::Reference
<io::XStream
> xStream
=
2357 comphelper::OStorageHelper::GetStreamAtPackageURL(mxSBD
->getDocumentStorage(), aUrl
,
2358 css::embed::ElementModes::READ
, aProxy
);
2360 uno::Reference
<io::XInputStream
> xInStream
= xStream
->getInputStream();
2363 sal_Int32 nLastDot
= aUrl
.lastIndexOf('.');
2364 sal_Int32 nLastSlash
= aUrl
.lastIndexOf('/');
2365 OUString sDesiredExtension
;
2366 if (nLastDot
> nLastSlash
&& nLastDot
+1 < aUrl
.getLength())
2367 sDesiredExtension
= aUrl
.copy(nLastDot
);
2370 if (::avmedia::CreateMediaTempFile(xInStream
, sTempUrl
, sDesiredExtension
))
2371 aRet
= std::make_shared
<avmedia::MediaTempFile
>(sTempUrl
);
2373 xInStream
->closeInput();
2379 //===== FrameSynchronization ==================================================
2381 FrameSynchronization::FrameSynchronization (const double nFrameDuration
)
2383 mnFrameDuration(nFrameDuration
),
2384 mnNextFrameTargetTime(0),
2390 void FrameSynchronization::MarkCurrentFrame()
2392 mnNextFrameTargetTime
= maTimer
.getElapsedTime() + mnFrameDuration
;
2395 void FrameSynchronization::Synchronize()
2399 // Do busy waiting for now.
2402 double remainingTime
= mnNextFrameTargetTime
- maTimer
.getElapsedTime();
2403 if(remainingTime
<= 0)
2405 // Try to sleep most of it.
2406 int remainingMilliseconds
= remainingTime
* 1000;
2407 if(remainingMilliseconds
> 2)
2408 osl::Thread::wait(std::chrono::milliseconds(remainingMilliseconds
- 2));
2415 void FrameSynchronization::Activate()
2420 void FrameSynchronization::Deactivate()
2427 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2428 slideshow_SlideShowImpl_get_implementation(
2429 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
2431 return cppu::acquire(new SlideShowImpl(context
));
2433 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */