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/factory.hxx>
26 #include <cppuhelper/implementationentry.hxx>
27 #include <cppuhelper/interfacecontainer.h>
28 #include <cppuhelper/exc_hlp.hxx>
30 #include <comphelper/anytostring.hxx>
31 #include <comphelper/make_shared_from_uno.hxx>
32 #include <comphelper/scopeguard.hxx>
33 #include <comphelper/servicedecl.hxx>
34 #include <comphelper/namecontainer.hxx>
36 #include <cppcanvas/spritecanvas.hxx>
37 #include <cppcanvas/vclfactory.hxx>
38 #include <cppcanvas/basegfxfactory.hxx>
40 #include <tools/debug.hxx>
42 #include <basegfx/point/b2dpoint.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <basegfx/matrix/b2dhommatrix.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <basegfx/polygon/b2dpolypolygontools.hxx>
47 #include <basegfx/utils/canvastools.hxx>
49 #include <vcl/font.hxx>
50 #include <rtl/ref.hxx>
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #include <com/sun/star/util/XModifyListener.hpp>
54 #include <com/sun/star/util/XUpdatable.hpp>
55 #include <com/sun/star/awt/XPaintListener.hpp>
56 #include <com/sun/star/awt/SystemPointer.hpp>
57 #include <com/sun/star/animations/TransitionType.hpp>
58 #include <com/sun/star/animations/TransitionSubType.hpp>
59 #include <com/sun/star/presentation/XSlideShow.hpp>
60 #include <com/sun/star/presentation/XSlideShowListener.hpp>
61 #include <com/sun/star/lang/NoSupportException.hpp>
62 #include <com/sun/star/lang/XServiceInfo.hpp>
63 #include <com/sun/star/lang/XServiceName.hpp>
64 #include <com/sun/star/lang/XComponent.hpp>
65 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
66 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
67 #include <com/sun/star/drawing/PointSequence.hpp>
68 #include <com/sun/star/drawing/XLayer.hpp>
69 #include <com/sun/star/drawing/XLayerSupplier.hpp>
70 #include <com/sun/star/drawing/XLayerManager.hpp>
71 #include <com/sun/star/container/XNameAccess.hpp>
73 #include <com/sun/star/uno/Reference.hxx>
74 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
76 #include <unoviewcontainer.hxx>
77 #include <transitionfactory.hxx>
78 #include <eventmultiplexer.hxx>
79 #include <usereventqueue.hxx>
80 #include <eventqueue.hxx>
81 #include <cursormanager.hxx>
82 #include <slideshowcontext.hxx>
83 #include <activitiesqueue.hxx>
84 #include <activitiesfactory.hxx>
85 #include <interruptabledelayevent.hxx>
87 #include <shapemaps.hxx>
88 #include <slideview.hxx>
90 #include <unoview.hxx>
91 #include <slidebitmap.hxx>
92 #include "rehearsetimingsactivity.hxx"
93 #include "waitsymbol.hxx"
94 #include "effectrewinder.hxx"
95 #include <framerate.hxx>
96 #include "pointersymbol.hxx"
106 using namespace com::sun::star
;
107 using namespace ::slideshow::internal
;
111 /** During animations the update() method tells its caller to call it as
112 soon as possible. This gives us more time to render the next frame and
113 still maintain a steady frame rate. This class is responsible for
114 synchronizing the display of new frames and thus keeping the frame rate
117 class FrameSynchronization
120 /** Create new object with a predefined duration between two frames.
121 @param nFrameDuration
122 The preferred duration between the display of two frames in
125 explicit FrameSynchronization (const double nFrameDuration
);
127 /** Set the current time as the time at which the current frame is
128 displayed. From this the target time of the next frame is derived.
130 void MarkCurrentFrame();
132 /** When there is time left until the next frame is due then wait.
133 Otherwise return without delay.
137 /** Activate frame synchronization when an animation is active and
138 frames are to be displayed in a steady rate. While active
139 Synchronize() will wait until the frame duration time has passed.
143 /** Deactivate frame sychronization when no animation is active and the
144 time between frames depends on user actions and other external
145 sources. While deactivated Synchronize() will return without delay.
150 /** The timer that is used for synchronization is independent from the
151 one used by SlideShowImpl: it is not paused or modified by
154 canvas::tools::ElapsedTime maTimer
;
155 /** Time between the display of frames. Enforced only when mbIsActive
158 const double mnFrameDuration
;
159 /** Time (of maTimer) when the next frame shall be displayed.
160 Synchronize() will wait until this time.
162 double mnNextFrameTargetTime
;
163 /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
164 it returns immediately.
169 /******************************************************************************
173 This class encapsulates the slideshow presentation viewer.
175 With an instance of this class, it is possible to statically
176 and dynamically show a presentation, as defined by the
177 constructor-provided draw model (represented by a sequence
178 of css::drawing::XDrawPage objects).
180 It is possible to show the presentation on multiple views
181 simultaneously (e.g. for a multi-monitor setup). Since this
182 class also relies on user interaction, the corresponding
183 XSlideShowView interface provides means to register some UI
184 event listeners (mostly borrowed from awt::XWindow interface).
186 Since currently (mid 2004), OOo isn't very well suited to
187 multi-threaded rendering, this class relies on <em>very
188 frequent</em> external update() calls, which will render the
189 next frame of animations. This works as follows: after the
190 displaySlide() has been successfully called (which setup and
191 starts an actual slide show), the update() method must be
192 called until it returns false.
193 Effectively, this puts the burden of providing
194 concurrency to the clients of this class, which, as noted
195 above, is currently unavoidable with the current state of
196 affairs (I've actually tried threading here, but failed
197 miserably when using the VCL canvas as the render backend -
200 ******************************************************************************/
202 typedef cppu::WeakComponentImplHelper
<presentation::XSlideShow
> SlideShowImplBase
;
204 typedef ::std::vector
< ::cppcanvas::PolyPolygonSharedPtr
> PolyPolygonVector
;
206 /// Maps XDrawPage for annotations persistence
207 typedef ::std::map
< css::uno::Reference
<
208 css::drawing::XDrawPage
>,
209 PolyPolygonVector
> PolygonMap
;
211 class SlideShowImpl
: private cppu::BaseMutex
,
212 public CursorManager
,
213 public SlideShowImplBase
216 explicit SlideShowImpl(
217 uno::Reference
<uno::XComponentContext
> const& xContext
);
219 /** Notify that the transition phase of the current slide
222 The life of a slide has three phases: the transition
223 phase, when the previous slide vanishes, and the
224 current slide becomes visible, the shape animation
225 phase, when shape effects are running, and the phase
226 after the last shape animation has ended, but before
227 the next slide transition starts.
229 This method notifies the end of the first phase.
232 When true, Slide::show() is passed a true as well, denoting
233 explicit paint of slide content. Pass false here, if e.g. a
234 slide transition has already rendered the initial slide image.
236 void notifySlideTransitionEnded( bool bPaintSlide
);
238 /** Notify that the shape animation phase of the current slide
241 The life of a slide has three phases: the transition
242 phase, when the previous slide vanishes, and the
243 current slide becomes visible, the shape animation
244 phase, when shape effects are running, and the phase
245 after the last shape animation has ended, but before
246 the next slide transition starts.
248 This method notifies the end of the second phase.
250 void notifySlideAnimationsEnded();
252 /** Notify that the slide has ended.
254 The life of a slide has three phases: the transition
255 phase, when the previous slide vanishes, and the
256 current slide becomes visible, the shape animation
257 phase, when shape effects are running, and the phase
258 after the last shape animation has ended, but before
259 the next slide transition starts.
261 This method notifies the end of the third phase.
263 void notifySlideEnded (const bool bReverse
);
265 /** Notification from eventmultiplexer that a hyperlink
268 bool notifyHyperLinkClicked( OUString
const& hyperLink
);
270 /** Notification from eventmultiplexer that an animation event has occoured.
271 This will be forewarded to all registered XSlideShowListener
273 bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
);
277 virtual sal_Bool SAL_CALL
nextEffect() override
;
278 virtual sal_Bool SAL_CALL
previousEffect() override
;
279 virtual sal_Bool SAL_CALL
startShapeActivity(
280 uno::Reference
<drawing::XShape
> const& xShape
) override
;
281 virtual sal_Bool SAL_CALL
stopShapeActivity(
282 uno::Reference
<drawing::XShape
> const& xShape
) override
;
283 virtual sal_Bool SAL_CALL
pause( sal_Bool bPauseShow
) override
;
284 virtual uno::Reference
<drawing::XDrawPage
> SAL_CALL
getCurrentSlide() override
;
285 virtual void SAL_CALL
displaySlide(
286 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
287 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
288 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
289 uno::Sequence
<beans::PropertyValue
> const& rProperties
) override
;
290 virtual void SAL_CALL
registerUserPaintPolygons( const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xDocFactory
) override
;
291 virtual sal_Bool SAL_CALL
setProperty(
292 beans::PropertyValue
const& rProperty
) override
;
293 virtual sal_Bool SAL_CALL
addView(
294 uno::Reference
<presentation::XSlideShowView
> const& xView
) override
;
295 virtual sal_Bool SAL_CALL
removeView(
296 uno::Reference
<presentation::XSlideShowView
> const& xView
) override
;
297 virtual sal_Bool SAL_CALL
update( double & nNextTimeout
) override
;
298 virtual void SAL_CALL
addSlideShowListener(
299 uno::Reference
<presentation::XSlideShowListener
> const& xListener
) override
;
300 virtual void SAL_CALL
removeSlideShowListener(
301 uno::Reference
<presentation::XSlideShowListener
> const& xListener
) override
;
302 virtual void SAL_CALL
addShapeEventListener(
303 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
304 uno::Reference
<drawing::XShape
> const& xShape
) override
;
305 virtual void SAL_CALL
removeShapeEventListener(
306 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
307 uno::Reference
<drawing::XShape
> const& xShape
) override
;
308 virtual void SAL_CALL
setShapeCursor(
309 uno::Reference
<drawing::XShape
> const& xShape
, sal_Int16 nPointerShape
) override
;
314 virtual bool requestCursor( sal_Int16 nCursorShape
) override
;
315 virtual void resetCursor() override
;
317 /** This is somewhat similar to displaySlide when called for the current
318 slide. It has been simplified to take advantage of that no slide
319 change takes place. Furthermore it does not show the slide
322 void redisplayCurrentSlide();
325 // WeakComponentImplHelperBase
326 virtual void SAL_CALL
disposing() override
;
328 bool isDisposed() const
330 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
334 struct SeparateListenerImpl
; friend struct SeparateListenerImpl
;
335 class PrefetchPropertiesFunc
; friend class PrefetchPropertiesFunc
;
337 /// Stop currently running show.
340 ///Find a polygons vector in maPolygons (map)
341 PolygonMap::iterator
findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
);
343 /// Creates a new slide.
344 SlideSharedPtr
makeSlide(
345 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
346 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
347 uno::Reference
<animations::XAnimationNode
> const& xRootNode
);
349 /// Checks whether the given slide/animation node matches mpPrefetchSlide
351 SlideSharedPtr
const& pSlide
,
352 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
353 uno::Reference
<animations::XAnimationNode
> const& xNode
)
356 return (pSlide
->getXDrawPage() == xSlide
&&
357 pSlide
->getXAnimationNode() == xNode
);
359 return (!xSlide
.is() && !xNode
.is());
362 /// Resets the current slide transition sound object with a new one:
363 SoundPlayerSharedPtr
resetSlideTransitionSound(
364 uno::Any
const& url
, bool bLoopSound
);
366 /// stops the current slide transition sound
367 void stopSlideTransitionSound();
369 /** Prepare a slide transition
371 This method registers all necessary events and
372 activities for a slide transition.
374 @return the slide change activity, or NULL for no transition effect
376 ActivitySharedPtr
createSlideTransition(
377 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
378 const SlideSharedPtr
& rLeavingSlide
,
379 const SlideSharedPtr
& rEnteringSlide
,
380 const EventSharedPtr
& rTransitionEndEvent
);
382 /** Request/release the wait symbol. The wait symbol is displayed when
383 there are more requests then releases. Locking the wait symbol
384 helps to avoid intermediate repaints.
386 Do not call this method directly. Use WaitSymbolLock instead.
388 void requestWaitSymbol();
389 void releaseWaitSymbol();
391 class WaitSymbolLock
{public:
392 explicit WaitSymbolLock(SlideShowImpl
& rSlideShowImpl
) : mrSlideShowImpl(rSlideShowImpl
)
393 { mrSlideShowImpl
.requestWaitSymbol(); }
395 { mrSlideShowImpl
.releaseWaitSymbol(); }
396 private: SlideShowImpl
& mrSlideShowImpl
;
399 /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
400 sal_Int16
calcActiveCursor( sal_Int16 nCursorShape
) const;
402 /** This method is called asynchronously to finish the rewinding of an
403 effect to the previous slide that was initiated earlier.
405 void rewindEffectToPreviousSlide();
407 /// all registered views
408 UnoViewContainer maViewContainer
;
410 /// all registered slide show listeners
411 comphelper::OInterfaceContainerHelper2 maListenerContainer
;
413 /// map of vectors, containing all registered listeners for a shape
414 ShapeEventListenerMap maShapeEventListeners
;
415 /// map of sal_Int16 values, specifying the mouse cursor for every shape
416 ShapeCursorMap maShapeCursors
;
418 //map of vector of Polygons, containing polygons drawn on each slide.
419 PolygonMap maPolygons
;
421 boost::optional
<RGBColor
> maUserPaintColor
;
423 double maUserPaintStrokeWidth
;
425 //changed for the eraser project
426 boost::optional
<bool> maEraseAllInk
;
427 boost::optional
<bool> maSwitchPenMode
;
428 boost::optional
<bool> maSwitchEraserMode
;
429 boost::optional
<sal_Int32
> maEraseInk
;
432 std::shared_ptr
<canvas::tools::ElapsedTime
> mpPresTimer
;
433 ScreenUpdater maScreenUpdater
;
434 EventQueue maEventQueue
;
435 EventMultiplexer maEventMultiplexer
;
436 ActivitiesQueue maActivitiesQueue
;
437 UserEventQueue maUserEventQueue
;
438 SubsettableShapeManagerSharedPtr mpDummyPtr
;
440 std::shared_ptr
<SeparateListenerImpl
> mpListener
;
442 std::shared_ptr
<RehearseTimingsActivity
> mpRehearseTimingsActivity
;
443 std::shared_ptr
<WaitSymbol
> mpWaitSymbol
;
445 std::shared_ptr
<PointerSymbol
> mpPointerSymbol
;
447 /// the current slide transition sound object:
448 SoundPlayerSharedPtr mpCurrentSlideTransitionSound
;
450 uno::Reference
<uno::XComponentContext
> mxComponentContext
;
452 presentation::XTransitionFactory
> mxOptionalTransitionFactory
;
454 /// the previously running slide
455 SlideSharedPtr mpPreviousSlide
;
456 /// the currently running slide
457 SlideSharedPtr mpCurrentSlide
;
458 /// the already prefetched slide: best candidate for upcoming slide
459 SlideSharedPtr mpPrefetchSlide
;
460 /// slide to be prefetched: best candidate for upcoming slide
461 uno::Reference
<drawing::XDrawPage
> mxPrefetchSlide
;
462 /// save the XDrawPagesSupplier to retrieve polygons
463 uno::Reference
<drawing::XDrawPagesSupplier
> mxDrawPagesSupplier
;
464 /// slide animation to be prefetched:
465 uno::Reference
<animations::XAnimationNode
> mxPrefetchAnimationNode
;
467 sal_Int16 mnCurrentCursor
;
469 sal_Int32 mnWaitSymbolRequestCount
;
470 bool mbAutomaticAdvancementMode
;
471 bool mbImageAnimationsAllowed
;
472 bool mbNoSlideTransitions
;
474 bool mbForceManualAdvance
;
476 bool mbSlideShowIdle
;
477 bool mbDisableAnimationZOrder
;
479 EffectRewinder maEffectRewinder
;
480 FrameSynchronization maFrameSynchronization
;
483 /** Separate event listener for animation, view and hyperlink events.
485 This handler is registered for slide animation end, view and
486 hyperlink events at the global EventMultiplexer, and forwards
487 notifications to the SlideShowImpl
489 struct SlideShowImpl::SeparateListenerImpl
: public EventHandler
,
490 public ViewRepaintHandler
,
491 public HyperlinkHandler
,
492 public AnimationEventHandler
494 SlideShowImpl
& mrShow
;
495 ScreenUpdater
& mrScreenUpdater
;
496 EventQueue
& mrEventQueue
;
498 SeparateListenerImpl( SlideShowImpl
& rShow
,
499 ScreenUpdater
& rScreenUpdater
,
500 EventQueue
& rEventQueue
) :
502 mrScreenUpdater( rScreenUpdater
),
503 mrEventQueue( rEventQueue
)
506 SeparateListenerImpl( const SeparateListenerImpl
& ) = delete;
507 SeparateListenerImpl
& operator=( const SeparateListenerImpl
& ) = delete;
510 virtual bool handleEvent() override
512 // DON't call notifySlideAnimationsEnded()
513 // directly, but queue an event. handleEvent()
514 // might be called from e.g.
515 // showNext(), and notifySlideAnimationsEnded() must not be called
516 // in recursion. Note that the event is scheduled for the next
517 // frame so that its expensive execution does not come in between
518 // sprite hiding and shape redraw (at the end of the animation of a
519 // shape), which would cause a flicker.
520 mrEventQueue
.addEventForNextRound(
521 makeEvent( [this] () { this->mrShow
.notifySlideAnimationsEnded(); },
522 "SlideShowImpl::notifySlideAnimationsEnded"));
526 // ViewRepaintHandler
527 virtual void viewClobbered( const UnoViewSharedPtr
& rView
) override
529 // given view needs repaint, request update
530 mrScreenUpdater
.notifyUpdate(rView
, true);
534 virtual bool handleHyperlink( OUString
const& rLink
) override
536 return mrShow
.notifyHyperLinkClicked(rLink
);
539 // AnimationEventHandler
540 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
) override
542 return mrShow
.handleAnimationEvent(rNode
);
546 SlideShowImpl::SlideShowImpl(
547 uno::Reference
<uno::XComponentContext
> const& xContext
)
548 : SlideShowImplBase(m_aMutex
),
550 maListenerContainer( m_aMutex
),
551 maShapeEventListeners(),
554 maUserPaintStrokeWidth(4.0),
555 mpPresTimer( new canvas::tools::ElapsedTime
),
556 maScreenUpdater(maViewContainer
),
557 maEventQueue( mpPresTimer
),
558 maEventMultiplexer( maEventQueue
,
560 maActivitiesQueue( mpPresTimer
),
561 maUserEventQueue( maEventMultiplexer
,
566 mpRehearseTimingsActivity(),
569 mpCurrentSlideTransitionSound(),
570 mxComponentContext( xContext
),
571 mxOptionalTransitionFactory(),
575 mxDrawPagesSupplier(),
576 mxPrefetchAnimationNode(),
577 mnCurrentCursor(awt::SystemPointer::ARROW
),
578 mnWaitSymbolRequestCount(0),
579 mbAutomaticAdvancementMode(false),
580 mbImageAnimationsAllowed( true ),
581 mbNoSlideTransitions( false ),
582 mbMouseVisible( true ),
583 mbForceManualAdvance( false ),
584 mbShowPaused( false ),
585 mbSlideShowIdle( true ),
586 mbDisableAnimationZOrder( false ),
587 maEffectRewinder(maEventMultiplexer
, maEventQueue
, maUserEventQueue
),
588 maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond
)
591 // keep care not constructing any UNO references to this inside ctor,
592 // shift that code to create()!
594 uno::Reference
<lang::XMultiComponentFactory
> xFactory(
595 mxComponentContext
->getServiceManager() );
601 // #i82460# try to retrieve special transition factory
602 mxOptionalTransitionFactory
.set(
603 xFactory
->createInstanceWithContext(
604 "com.sun.star.presentation.TransitionFactory",
605 mxComponentContext
),
608 catch (loader::CannotActivateFactoryException
const&)
613 mpListener
.reset( new SeparateListenerImpl(
617 maEventMultiplexer
.addSlideAnimationsEndHandler( mpListener
);
618 maEventMultiplexer
.addViewRepaintHandler( mpListener
);
619 maEventMultiplexer
.addHyperlinkHandler( mpListener
, 0.0 );
620 maEventMultiplexer
.addAnimationStartHandler( mpListener
);
621 maEventMultiplexer
.addAnimationEndHandler( mpListener
);
624 // we are about to be disposed (someone call dispose() on us)
625 void SlideShowImpl::disposing()
627 osl::MutexGuard
const guard( m_aMutex
);
629 maEffectRewinder
.dispose();
631 // stop slide transition sound, if any:
632 stopSlideTransitionSound();
634 mxComponentContext
.clear();
636 if( mpCurrentSlideTransitionSound
)
638 mpCurrentSlideTransitionSound
->dispose();
639 mpCurrentSlideTransitionSound
.reset();
642 mpWaitSymbol
.reset();
643 mpPointerSymbol
.reset();
645 if( mpRehearseTimingsActivity
)
647 mpRehearseTimingsActivity
->dispose();
648 mpRehearseTimingsActivity
.reset();
653 maEventMultiplexer
.removeSlideAnimationsEndHandler(mpListener
);
654 maEventMultiplexer
.removeViewRepaintHandler(mpListener
);
655 maEventMultiplexer
.removeHyperlinkHandler(mpListener
);
656 maEventMultiplexer
.removeAnimationStartHandler( mpListener
);
657 maEventMultiplexer
.removeAnimationEndHandler( mpListener
);
662 maUserEventQueue
.clear();
663 maActivitiesQueue
.clear();
664 maEventMultiplexer
.clear();
665 maEventQueue
.clear();
667 maShapeCursors
.clear();
668 maShapeEventListeners
.clear();
670 // send all listeners a disposing() that we are going down:
671 maListenerContainer
.disposeAndClear(
672 lang::EventObject( static_cast<cppu::OWeakObject
*>(this) ) );
674 maViewContainer
.dispose();
677 mxPrefetchAnimationNode
.clear();
678 mxPrefetchSlide
.clear();
679 mpPrefetchSlide
.reset();
680 mpCurrentSlide
.reset();
681 mpPreviousSlide
.reset();
684 /// stops the current slide transition sound
685 void SlideShowImpl::stopSlideTransitionSound()
687 if (mpCurrentSlideTransitionSound
)
689 mpCurrentSlideTransitionSound
->stopPlayback();
690 mpCurrentSlideTransitionSound
->dispose();
691 mpCurrentSlideTransitionSound
.reset();
695 SoundPlayerSharedPtr
SlideShowImpl::resetSlideTransitionSound( const uno::Any
& rSound
, bool bLoopSound
)
697 bool bStopSound
= false;
700 if( !(rSound
>>= bStopSound
) )
704 if( !bStopSound
&& url
.isEmpty() )
705 return SoundPlayerSharedPtr();
707 stopSlideTransitionSound();
713 mpCurrentSlideTransitionSound
= SoundPlayer::create(
714 maEventMultiplexer
, url
, mxComponentContext
);
715 mpCurrentSlideTransitionSound
->setPlaybackLoop( bLoopSound
);
717 catch (lang::NoSupportException
const&)
719 // catch possible exceptions from SoundPlayer, since
720 // being not able to playback the sound is not a hard
721 // error here (still, the slide transition should be
725 return mpCurrentSlideTransitionSound
;
728 ActivitySharedPtr
SlideShowImpl::createSlideTransition(
729 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
730 const SlideSharedPtr
& rLeavingSlide
,
731 const SlideSharedPtr
& rEnteringSlide
,
732 const EventSharedPtr
& rTransitionEndEvent
)
734 ENSURE_OR_THROW( !maViewContainer
.empty(),
735 "createSlideTransition(): No views" );
736 ENSURE_OR_THROW( rEnteringSlide
,
737 "createSlideTransition(): No entering slide" );
739 // return empty transition, if slide transitions
741 if (mbNoSlideTransitions
)
742 return ActivitySharedPtr();
744 // retrieve slide change parameters from XDrawPage
745 uno::Reference
< beans::XPropertySet
> xPropSet( xDrawPage
,
750 SAL_INFO("slideshow", "createSlideTransition(): "
751 "Slide has no PropertySet - assuming no transition" );
752 return ActivitySharedPtr();
755 sal_Int16
nTransitionType(0);
756 if( !getPropertyValue( nTransitionType
,
760 SAL_INFO("slideshow", "createSlideTransition(): "
761 "Could not extract slide transition type from XDrawPage - assuming no transition" );
762 return ActivitySharedPtr();
765 sal_Int16
nTransitionSubType(0);
766 if( !getPropertyValue( nTransitionSubType
,
768 "TransitionSubtype") )
770 SAL_INFO("slideshow", "createSlideTransition(): "
771 "Could not extract slide transition subtype from XDrawPage - assuming no transition" );
772 return ActivitySharedPtr();
775 bool bTransitionDirection(false);
776 if( !getPropertyValue( bTransitionDirection
,
778 "TransitionDirection") )
780 SAL_INFO("slideshow", "createSlideTransition(): "
781 "Could not extract slide transition direction from XDrawPage - assuming default direction" );
784 sal_Int32
aUnoColor(0);
785 if( !getPropertyValue( aUnoColor
,
787 "TransitionFadeColor") )
789 SAL_INFO("slideshow", "createSlideTransition(): "
790 "Could not extract slide transition fade color from XDrawPage - assuming black" );
793 const RGBColor
aTransitionFadeColor( unoColor2RGBColor( aUnoColor
));
796 bool bLoopSound
= false;
798 if( !getPropertyValue( aSound
, xPropSet
, "Sound") )
799 SAL_INFO("slideshow", "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound" );
801 if( !getPropertyValue( bLoopSound
, xPropSet
, "LoopSound" ) )
802 SAL_INFO("slideshow", "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound" );
804 NumberAnimationSharedPtr
pTransition(
805 TransitionFactory::createSlideTransition(
811 mxOptionalTransitionFactory
,
814 bTransitionDirection
,
815 aTransitionFadeColor
,
816 resetSlideTransitionSound( aSound
, bLoopSound
) ));
819 return ActivitySharedPtr(); // no transition effect has been
820 // generated. Normally, that means
821 // that simply no transition is
822 // set on this slide.
824 double nTransitionDuration(0.0);
825 if( !getPropertyValue( nTransitionDuration
,
827 "TransitionDuration") )
829 SAL_INFO("slideshow", "createSlideTransition(): "
830 "Could not extract slide transition duration from XDrawPage - assuming no transition" );
831 return ActivitySharedPtr();
834 sal_Int32
nMinFrames(5);
835 if( !getPropertyValue( nMinFrames
,
837 "MinimalFrameNumber") )
839 SAL_INFO("slideshow", "createSlideTransition(): "
840 "No minimal number of frames given - assuming 5" );
843 // prefetch slide transition bitmaps, but postpone it after
844 // displaySlide() has finished - sometimes, view size has not yet
845 // reached final size
846 maEventQueue
.addEvent(
847 makeEvent( [pTransition
] () {
848 pTransition
->prefetch(
849 AnimatableShapeSharedPtr(),
850 ShapeAttributeLayerSharedPtr()); },
851 "Animation::prefetch"));
853 return ActivitySharedPtr(
854 ActivitiesFactory::createSimpleActivity(
855 ActivitiesFactory::CommonParameters(
862 boost::optional
<double>(1.0),
866 basegfx::B2DSize( rEnteringSlide
->getSlideSize() ) ),
871 PolygonMap::iterator
SlideShowImpl::findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
)
873 // TODO(P2): optimize research in the map.
874 PolygonMap::iterator aEnd
= maPolygons
.end();
875 for( PolygonMap::iterator aIter
= maPolygons
.begin();
878 if( aIter
->first
== xDrawPage
)
884 SlideSharedPtr
SlideShowImpl::makeSlide(
885 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
886 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
887 uno::Reference
<animations::XAnimationNode
> const& xRootNode
)
889 if( !xDrawPage
.is() )
890 return SlideSharedPtr();
892 //Retrieve polygons for the current slide
893 PolygonMap::iterator aIter
;
894 aIter
= findPolygons(xDrawPage
);
896 const SlideSharedPtr
pSlide( createSlide(xDrawPage
,
907 maShapeEventListeners
,
909 (aIter
!= maPolygons
.end()) ? aIter
->second
: PolyPolygonVector(),
910 maUserPaintColor
? *maUserPaintColor
: RGBColor(),
911 maUserPaintStrokeWidth
,
913 mbImageAnimationsAllowed
,
914 mbDisableAnimationZOrder
) );
916 // prefetch show content (reducing latency for slide
917 // bitmap and effect start later on)
923 void SlideShowImpl::requestWaitSymbol()
925 ++mnWaitSymbolRequestCount
;
926 OSL_ASSERT(mnWaitSymbolRequestCount
>0);
928 if (mnWaitSymbolRequestCount
== 1)
932 // fall back to cursor
933 requestCursor(calcActiveCursor(mnCurrentCursor
));
936 mpWaitSymbol
->show();
940 void SlideShowImpl::releaseWaitSymbol()
942 --mnWaitSymbolRequestCount
;
943 OSL_ASSERT(mnWaitSymbolRequestCount
>=0);
945 if (mnWaitSymbolRequestCount
== 0)
949 // fall back to cursor
950 requestCursor(calcActiveCursor(mnCurrentCursor
));
953 mpWaitSymbol
->hide();
957 sal_Int16
SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape
) const
959 if( mnWaitSymbolRequestCount
>0 && !mpWaitSymbol
) // enforce wait cursor
960 nCursorShape
= awt::SystemPointer::WAIT
;
961 else if( !mbMouseVisible
) // enforce INVISIBLE
962 nCursorShape
= awt::SystemPointer::INVISIBLE
;
963 else if( maUserPaintColor
&&
964 nCursorShape
== awt::SystemPointer::ARROW
)
965 nCursorShape
= awt::SystemPointer::PEN
;
970 void SlideShowImpl::stopShow()
972 // Force-end running animation
973 // ===========================
976 mpCurrentSlide
->hide();
977 //Register polygons in the map
978 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
979 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
981 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
985 maEventQueue
.clear();
986 maActivitiesQueue
.clear();
988 // Attention: we MUST clear the user event queue here,
989 // this is because the current slide might have registered
990 // shape events (click or enter/leave), which might
991 // otherwise dangle forever in the queue (because of the
992 // shared ptr nature). If someone needs to change this:
993 // somehow unregister those shapes at the user event queue
994 // on notifySlideEnded().
995 maUserEventQueue
.clear();
997 // re-enable automatic effect advancement
998 // (maEventQueue.clear() above might have killed
999 // maEventMultiplexer's tick events)
1000 if (mbAutomaticAdvancementMode
)
1002 // toggle automatic mode (enabling just again is
1003 // ignored by EventMultiplexer)
1004 maEventMultiplexer
.setAutomaticMode( false );
1005 maEventMultiplexer
.setAutomaticMode( true );
1009 class SlideShowImpl::PrefetchPropertiesFunc
1012 PrefetchPropertiesFunc( SlideShowImpl
* that_
,
1013 bool& rbSkipAllMainSequenceEffects
,
1014 bool& rbSkipSlideTransition
)
1015 : mpSlideShowImpl(that_
),
1016 mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects
),
1017 mrbSkipSlideTransition(rbSkipSlideTransition
)
1020 void operator()( beans::PropertyValue
const& rProperty
) const {
1021 if (rProperty
.Name
== "Prefetch" )
1023 uno::Sequence
<uno::Any
> seq
;
1024 if ((rProperty
.Value
>>= seq
) && seq
.getLength() == 2)
1026 seq
[0] >>= mpSlideShowImpl
->mxPrefetchSlide
;
1027 seq
[1] >>= mpSlideShowImpl
->mxPrefetchAnimationNode
;
1030 else if ( rProperty
.Name
== "SkipAllMainSequenceEffects" )
1032 rProperty
.Value
>>= mrbSkipAllMainSequenceEffects
;
1034 else if ( rProperty
.Name
== "SkipSlideTransition" )
1036 rProperty
.Value
>>= mrbSkipSlideTransition
;
1040 SAL_WARN( "slideshow", rProperty
.Name
);
1044 SlideShowImpl
*const mpSlideShowImpl
;
1045 bool& mrbSkipAllMainSequenceEffects
;
1046 bool& mrbSkipSlideTransition
;
1049 void SlideShowImpl::displaySlide(
1050 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
1051 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
1052 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
1053 uno::Sequence
<beans::PropertyValue
> const& rProperties
)
1055 osl::MutexGuard
const guard( m_aMutex
);
1060 maEffectRewinder
.setRootAnimationNode(xRootNode
);
1062 // precondition: must only be called from the main thread!
1063 DBG_TESTSOLARMUTEX();
1065 mxDrawPagesSupplier
= xDrawPages
;
1067 stopShow(); // MUST call that: results in
1068 // maUserEventQueue.clear(). What's more,
1069 // stopShow()'s currSlide->hide() call is
1070 // now also required, notifySlideEnded()
1072 // unconditionally. Otherwise, genuine
1073 // shape animations (drawing layer and
1074 // GIF) will not be stopped.
1076 bool bSkipAllMainSequenceEffects (false);
1077 bool bSkipSlideTransition (false);
1078 std::for_each( rProperties
.begin(),
1080 PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects
, bSkipSlideTransition
) );
1082 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1083 if (maViewContainer
.empty())
1086 // this here might take some time
1088 WaitSymbolLock
aLock (*this);
1090 mpPreviousSlide
= mpCurrentSlide
;
1091 mpCurrentSlide
.reset();
1093 if (matches( mpPrefetchSlide
, xSlide
, xRootNode
))
1095 // prefetched slide matches:
1096 mpCurrentSlide
= mpPrefetchSlide
;
1099 mpCurrentSlide
= makeSlide( xSlide
, xDrawPages
, xRootNode
);
1101 OSL_ASSERT( mpCurrentSlide
);
1104 basegfx::B2DSize oldSlideSize
;
1105 if( mpPreviousSlide
)
1106 oldSlideSize
= basegfx::B2DSize( mpPreviousSlide
->getSlideSize() );
1108 basegfx::B2DSize
const slideSize( mpCurrentSlide
->getSlideSize() );
1110 // push new transformation to all views, if size changed
1111 if( !mpPreviousSlide
|| oldSlideSize
!= slideSize
)
1113 for( const auto& pView
: maViewContainer
)
1114 pView
->setViewSize( slideSize
);
1116 // explicitly notify view change here,
1117 // because transformation might have changed:
1118 // optimization, this->notifyViewChange() would
1119 // repaint slide which is not necessary.
1120 maEventMultiplexer
.notifyViewsChanged();
1123 // create slide transition, and add proper end event
1124 // (which then starts the slide effects
1125 // via CURRENT_SLIDE.show())
1126 ActivitySharedPtr
pSlideChangeActivity (
1127 createSlideTransition(
1128 mpCurrentSlide
->getXDrawPage(),
1132 [this] () { this->notifySlideTransitionEnded(false); },
1133 "SlideShowImpl::notifySlideTransitionEnded")));
1135 if (bSkipSlideTransition
)
1137 // The transition activity was created for the side effects
1138 // (like sound transitions). Because we want to skip the
1139 // actual transition animation we do not need the activity
1141 pSlideChangeActivity
.reset();
1144 if (pSlideChangeActivity
)
1146 // factory generated a slide transition - activate it!
1147 maActivitiesQueue
.addActivity( pSlideChangeActivity
);
1151 // no transition effect on this slide - schedule slide
1152 // effect start event right away.
1153 maEventQueue
.addEvent(
1155 [this] () { this->notifySlideTransitionEnded(true); },
1156 "SlideShowImpl::notifySlideTransitionEnded"));
1161 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1162 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1164 xListener
->slideTransitionStarted();
1167 // We are currently rewinding an effect. This lead us from the next
1168 // slide to this one. To complete this we have to play back all main
1169 // sequence effects on this slide.
1170 if (bSkipAllMainSequenceEffects
)
1171 maEffectRewinder
.skipAllMainSequenceEffects();
1174 void SlideShowImpl::redisplayCurrentSlide()
1176 osl::MutexGuard
const guard( m_aMutex
);
1181 // precondition: must only be called from the main thread!
1182 DBG_TESTSOLARMUTEX();
1185 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1186 if (maViewContainer
.empty())
1189 // No transition effect on this slide - schedule slide
1190 // effect start event right away.
1191 maEventQueue
.addEvent(
1192 makeEvent( [this] () { this->notifySlideTransitionEnded(true); },
1193 "SlideShowImpl::notifySlideTransitionEnded"));
1195 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1196 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1198 xListener
->slideTransitionStarted();
1202 sal_Bool
SlideShowImpl::nextEffect()
1204 osl::MutexGuard
const guard( m_aMutex
);
1209 // precondition: must only be called from the main thread!
1210 DBG_TESTSOLARMUTEX();
1215 return maEventMultiplexer
.notifyNextEffect();
1218 sal_Bool
SlideShowImpl::previousEffect()
1220 osl::MutexGuard
const guard( m_aMutex
);
1225 // precondition: must only be called from the main thread!
1226 DBG_TESTSOLARMUTEX();
1232 return maEffectRewinder
.rewind(
1233 maScreenUpdater
.createLock(),
1234 [this]() { return this->redisplayCurrentSlide(); },
1235 [this]() { return this->rewindEffectToPreviousSlide(); } );
1239 void SlideShowImpl::rewindEffectToPreviousSlide()
1241 // Show the wait symbol now and prevent it from showing temporary slide
1242 // content while effects are played back.
1243 WaitSymbolLock
aLock (*this);
1245 // A previous call to EffectRewinder::Rewind could not rewind the current
1246 // effect because there are no effects on the current slide or none has
1247 // yet been displayed. Go to the previous slide.
1248 notifySlideEnded(true);
1250 // Process pending events once more in order to have the following
1251 // screen update show the last effect. Not sure whether this should be
1253 maEventQueue
.forceEmpty();
1255 // We have to call the screen updater before the wait symbol is turned
1256 // off. Otherwise the wait symbol would force the display of an
1257 // intermediate state of the slide (before the effects are replayed.)
1258 maScreenUpdater
.commitUpdates();
1261 sal_Bool
SlideShowImpl::startShapeActivity(
1262 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1264 osl::MutexGuard
const guard( m_aMutex
);
1266 // precondition: must only be called from the main thread!
1267 DBG_TESTSOLARMUTEX();
1270 OSL_FAIL( "not yet implemented!" );
1274 sal_Bool
SlideShowImpl::stopShapeActivity(
1275 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1277 osl::MutexGuard
const guard( m_aMutex
);
1279 // precondition: must only be called from the main thread!
1280 DBG_TESTSOLARMUTEX();
1283 OSL_FAIL( "not yet implemented!" );
1287 sal_Bool
SlideShowImpl::pause( sal_Bool bPauseShow
)
1289 osl::MutexGuard
const guard( m_aMutex
);
1294 // precondition: must only be called from the main thread!
1295 DBG_TESTSOLARMUTEX();
1298 mpPresTimer
->pauseTimer();
1300 mpPresTimer
->continueTimer();
1302 maEventMultiplexer
.notifyPauseMode(bPauseShow
);
1304 mbShowPaused
= bPauseShow
;
1308 uno::Reference
<drawing::XDrawPage
> SlideShowImpl::getCurrentSlide()
1310 osl::MutexGuard
const guard( m_aMutex
);
1313 return uno::Reference
<drawing::XDrawPage
>();
1315 // precondition: must only be called from the main thread!
1316 DBG_TESTSOLARMUTEX();
1319 return mpCurrentSlide
->getXDrawPage();
1321 return uno::Reference
<drawing::XDrawPage
>();
1324 sal_Bool
SlideShowImpl::addView(
1325 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1327 osl::MutexGuard
const guard( m_aMutex
);
1332 // precondition: must only be called from the main thread!
1333 DBG_TESTSOLARMUTEX();
1335 // first of all, check if view has a valid canvas
1336 ENSURE_OR_RETURN_FALSE( xView
.is(), "addView(): Invalid view" );
1337 ENSURE_OR_RETURN_FALSE( xView
->getCanvas().is(),
1338 "addView(): View does not provide a valid canvas" );
1340 UnoViewSharedPtr
const pView( createSlideView(
1343 maEventMultiplexer
));
1344 if (!maViewContainer
.addView( pView
))
1345 return false; // view already added
1347 // initialize view content
1348 // =======================
1352 // set view transformation
1353 const basegfx::B2ISize slideSize
= mpCurrentSlide
->getSlideSize();
1354 pView
->setViewSize( basegfx::B2DSize( slideSize
.getX(),
1355 slideSize
.getY() ) );
1358 // clear view area (since its newly added,
1359 // we need a clean slate)
1362 // broadcast newly added view
1363 maEventMultiplexer
.notifyViewAdded( pView
);
1365 // set current mouse ptr
1366 pView
->setCursorShape( calcActiveCursor(mnCurrentCursor
) );
1371 sal_Bool
SlideShowImpl::removeView(
1372 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1374 osl::MutexGuard
const guard( m_aMutex
);
1376 // precondition: must only be called from the main thread!
1377 DBG_TESTSOLARMUTEX();
1379 ENSURE_OR_RETURN_FALSE( xView
.is(), "removeView(): Invalid view" );
1381 UnoViewSharedPtr
const pView( maViewContainer
.removeView( xView
) );
1383 return false; // view was not added in the first place
1385 // remove view from EventMultiplexer (mouse events etc.)
1386 maEventMultiplexer
.notifyViewRemoved( pView
);
1393 void SlideShowImpl::registerUserPaintPolygons( const uno::Reference
< lang::XMultiServiceFactory
>& xDocFactory
)
1395 //Retrieve Polygons if user ends presentation by context menu
1398 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
1399 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
1401 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
1404 //Creating the layer for shapes
1405 // query for the XLayerManager
1406 uno::Reference
< drawing::XLayerSupplier
> xLayerSupplier(xDocFactory
, uno::UNO_QUERY
);
1407 uno::Reference
< container::XNameAccess
> xNameAccess
= xLayerSupplier
->getLayerManager();
1409 uno::Reference
< drawing::XLayerManager
> xLayerManager(xNameAccess
, uno::UNO_QUERY
);
1410 // create a layer and set its properties
1411 uno::Reference
< drawing::XLayer
> xDrawnInSlideshow
= xLayerManager
->insertNewByIndex(xLayerManager
->getCount());
1412 uno::Reference
< beans::XPropertySet
> xLayerPropSet(xDrawnInSlideshow
, uno::UNO_QUERY
);
1414 //Layer Name which enables to catch annotations
1415 OUString layerName
= "DrawnInSlideshow";
1416 uno::Any aPropLayer
;
1418 aPropLayer
<<= layerName
;
1419 xLayerPropSet
->setPropertyValue("Name", aPropLayer
);
1421 aPropLayer
<<= true;
1422 xLayerPropSet
->setPropertyValue("IsVisible", aPropLayer
);
1424 aPropLayer
<<= false;
1425 xLayerPropSet
->setPropertyValue("IsLocked", aPropLayer
);
1427 //Register polygons for each slide
1428 for( const auto& rPoly
: maPolygons
)
1430 PolyPolygonVector aPolygons
= rPoly
.second
;
1431 //Get shapes for the slide
1432 css::uno::Reference
< css::drawing::XShapes
> Shapes(rPoly
.first
, css::uno::UNO_QUERY
);
1433 //Retrieve polygons for one slide
1434 for( const auto& pPolyPoly
: aPolygons
)
1436 ::basegfx::B2DPolyPolygon b2DPolyPoly
= ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly
->getUNOPolyPolygon());
1438 //Normally there is only one polygon
1439 for(sal_uInt32 i
=0; i
< b2DPolyPoly
.count();i
++)
1441 const ::basegfx::B2DPolygon
& aPoly
= b2DPolyPoly
.getB2DPolygon(i
);
1442 sal_uInt32 nPoints
= aPoly
.count();
1446 //create the PolyLineShape
1447 uno::Reference
< uno::XInterface
> polyshape(xDocFactory
->createInstance(
1448 "com.sun.star.drawing.PolyLineShape" ) );
1449 uno::Reference
< drawing::XShape
> rPolyShape(polyshape
, uno::UNO_QUERY
);
1451 //Add the shape to the slide
1452 Shapes
->add(rPolyShape
);
1454 //Retrieve shape properties
1455 uno::Reference
< beans::XPropertySet
> aXPropSet( rPolyShape
, uno::UNO_QUERY
);
1456 //Construct a sequence of points sequence
1457 drawing::PointSequenceSequence aRetval
;
1458 //Create only one sequence for one polygon
1459 aRetval
.realloc( 1 );
1460 // Retrieve the sequence of points from aRetval
1461 drawing::PointSequence
* pOuterSequence
= aRetval
.getArray();
1462 // Create 2 points in this sequence
1463 pOuterSequence
->realloc(nPoints
);
1464 // Get these points which are in an array
1465 awt::Point
* pInnerSequence
= pOuterSequence
->getArray();
1466 for( sal_uInt32 n
= 0; n
< nPoints
; n
++ )
1468 //Create a point from the polygon
1469 *pInnerSequence
++ = awt::Point(
1470 basegfx::fround(aPoly
.getB2DPoint(n
).getX()),
1471 basegfx::fround(aPoly
.getB2DPoint(n
).getY()));
1474 //Fill the properties
1475 //Give the built PointSequenceSequence.
1478 aXPropSet
->setPropertyValue("PolyPolygon", aParam
);
1480 //LineStyle : SOLID by default
1481 drawing::LineStyle eLS
;
1482 eLS
= drawing::LineStyle_SOLID
;
1483 aXPropSet
->setPropertyValue("LineStyle", uno::Any(eLS
) );
1486 sal_uInt32 nLineColor
;
1487 nLineColor
= pPolyPoly
->getRGBALineColor();
1488 //Transform polygon color from RRGGBBAA to AARRGGBB
1489 aXPropSet
->setPropertyValue("LineColor", uno::Any(RGBAColor2UnoColor(nLineColor
)) );
1493 fLineWidth
= pPolyPoly
->getStrokeWidth();
1494 aXPropSet
->setPropertyValue("LineWidth", uno::Any((sal_Int32
)fLineWidth
) );
1496 // make polygons special
1497 xLayerManager
->attachShapeToLayer(rPolyShape
, xDrawnInSlideshow
);
1504 sal_Bool
SlideShowImpl::setProperty( beans::PropertyValue
const& rProperty
)
1506 osl::MutexGuard
const guard( m_aMutex
);
1511 // precondition: must only be called from the main thread!
1512 DBG_TESTSOLARMUTEX();
1514 if ( rProperty
.Name
== "AutomaticAdvancement" )
1516 double nTimeout(0.0);
1517 mbAutomaticAdvancementMode
= (rProperty
.Value
>>= nTimeout
);
1518 if (mbAutomaticAdvancementMode
)
1520 maEventMultiplexer
.setAutomaticTimeout( nTimeout
);
1522 maEventMultiplexer
.setAutomaticMode( mbAutomaticAdvancementMode
);
1526 if ( rProperty
.Name
== "UserPaintColor" )
1528 sal_Int32
nColor(0);
1529 if (rProperty
.Value
>>= nColor
)
1531 OSL_ENSURE( mbMouseVisible
,
1532 "setProperty(): User paint overrides invisible mouse" );
1534 // enable user paint
1535 maUserPaintColor
.reset( unoColor2RGBColor( nColor
) );
1536 if( mpCurrentSlide
&& !mpCurrentSlide
->isPaintOverlayActive() )
1537 mpCurrentSlide
->enablePaintOverlay();
1539 maEventMultiplexer
.notifyUserPaintColor( *maUserPaintColor
);
1543 // disable user paint
1544 maUserPaintColor
.reset();
1545 maEventMultiplexer
.notifyUserPaintDisabled();
1546 if( mpCurrentSlide
)
1547 mpCurrentSlide
->disablePaintOverlay();
1555 //adding support for erasing features in UserPaintOverlay
1556 if ( rProperty
.Name
== "EraseAllInk" )
1558 bool bEraseAllInk(false);
1559 if (rProperty
.Value
>>= bEraseAllInk
)
1561 OSL_ENSURE( mbMouseVisible
,
1562 "setProperty(): User paint overrides invisible mouse" );
1564 // enable user paint
1565 maEraseAllInk
.reset( bEraseAllInk
);
1566 maEventMultiplexer
.notifyEraseAllInk( *maEraseAllInk
);
1572 if ( rProperty
.Name
== "SwitchPenMode" )
1574 bool bSwitchPenMode(false);
1575 if (rProperty
.Value
>>= bSwitchPenMode
)
1577 OSL_ENSURE( mbMouseVisible
,
1578 "setProperty(): User paint overrides invisible mouse" );
1581 // Switch to Pen Mode
1582 maSwitchPenMode
.reset( bSwitchPenMode
);
1583 maEventMultiplexer
.notifySwitchPenMode();
1589 if ( rProperty
.Name
== "SwitchEraserMode" )
1591 bool bSwitchEraserMode(false);
1592 if (rProperty
.Value
>>= bSwitchEraserMode
)
1594 OSL_ENSURE( mbMouseVisible
,
1595 "setProperty(): User paint overrides invisible mouse" );
1596 if(bSwitchEraserMode
){
1597 // switch to Eraser mode
1598 maSwitchEraserMode
.reset( bSwitchEraserMode
);
1599 maEventMultiplexer
.notifySwitchEraserMode();
1606 if ( rProperty
.Name
== "EraseInk" )
1608 sal_Int32
nEraseInk(100);
1609 if (rProperty
.Value
>>= nEraseInk
)
1611 OSL_ENSURE( mbMouseVisible
,
1612 "setProperty(): User paint overrides invisible mouse" );
1614 // enable user paint
1615 maEraseInk
.reset( nEraseInk
);
1616 maEventMultiplexer
.notifyEraseInkWidth( *maEraseInk
);
1622 // new Property for pen's width
1623 if ( rProperty
.Name
== "UserPaintStrokeWidth" )
1626 if (rProperty
.Value
>>= nWidth
)
1628 OSL_ENSURE( mbMouseVisible
,"setProperty(): User paint overrides invisible mouse" );
1629 // enable user paint stroke width
1630 maUserPaintStrokeWidth
= nWidth
;
1631 maEventMultiplexer
.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth
);
1637 if ( rProperty
.Name
== "AdvanceOnClick" )
1639 bool bAdvanceOnClick
= false;
1640 if (! (rProperty
.Value
>>= bAdvanceOnClick
))
1642 maUserEventQueue
.setAdvanceOnClick( bAdvanceOnClick
);
1646 if ( rProperty
.Name
== "DisableAnimationZOrder" )
1648 bool bDisableAnimationZOrder
= false;
1649 if (! (rProperty
.Value
>>= bDisableAnimationZOrder
))
1651 mbDisableAnimationZOrder
= bDisableAnimationZOrder
;
1655 if ( rProperty
.Name
== "ImageAnimationsAllowed" )
1657 if (! (rProperty
.Value
>>= mbImageAnimationsAllowed
))
1660 // TODO(F3): Forward to slides!
1664 if ( rProperty
.Name
== "MouseVisible" )
1666 if (! (rProperty
.Value
>>= mbMouseVisible
))
1669 requestCursor(mnCurrentCursor
);
1674 if ( rProperty
.Name
== "ForceManualAdvance" )
1676 return (rProperty
.Value
>>= mbForceManualAdvance
);
1679 if ( rProperty
.Name
== "RehearseTimings" )
1681 bool bRehearseTimings
= false;
1682 if (! (rProperty
.Value
>>= bRehearseTimings
))
1685 if (bRehearseTimings
)
1687 // TODO(Q3): Move to slide
1688 mpRehearseTimingsActivity
= RehearseTimingsActivity::create(
1698 mxComponentContext
) );
1700 else if (mpRehearseTimingsActivity
)
1702 // removes timer from all views:
1703 mpRehearseTimingsActivity
->dispose();
1704 mpRehearseTimingsActivity
.reset();
1709 if ( rProperty
.Name
== "WaitSymbolBitmap" )
1711 uno::Reference
<rendering::XBitmap
> xBitmap
;
1712 if (! (rProperty
.Value
>>= xBitmap
))
1715 mpWaitSymbol
= WaitSymbol::create( xBitmap
,
1723 if ( rProperty
.Name
== "PointerSymbolBitmap" )
1725 uno::Reference
<rendering::XBitmap
> xBitmap
;
1726 if (! (rProperty
.Value
>>= xBitmap
))
1729 mpPointerSymbol
= PointerSymbol::create( xBitmap
,
1737 if ( rProperty
.Name
== "PointerVisible" )
1740 if (!(rProperty
.Value
>>= visible
))
1743 mpPointerSymbol
->setVisible(visible
);
1747 if ( rProperty
.Name
== "PointerPosition")
1749 css::geometry::RealPoint2D pos
;
1750 if (! (rProperty
.Value
>>= pos
))
1753 mpPointerSymbol
->viewsChanged(pos
);
1757 if (rProperty
.Name
== "NoSlideTransitions" )
1759 return (rProperty
.Value
>>= mbNoSlideTransitions
);
1762 if ( rProperty
.Name
== "IsSoundEnabled" )
1764 uno::Sequence
<uno::Any
> aValues
;
1765 uno::Reference
<presentation::XSlideShowView
> xView
;
1766 bool bValue (false);
1767 if ((rProperty
.Value
>>= aValues
)
1768 && aValues
.getLength()==2
1769 && (aValues
[0] >>= xView
)
1770 && (aValues
[1] >>= bValue
))
1772 // Look up the view.
1773 for (UnoViewVector::const_iterator
1774 iView (maViewContainer
.begin()),
1775 iEnd (maViewContainer
.end());
1779 if (*iView
&& (*iView
)->getUnoView()==xView
)
1781 // Store the flag at the view so that media shapes have
1783 (*iView
)->setIsSoundEnabled(bValue
);
1793 void SlideShowImpl::addSlideShowListener(
1794 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1796 osl::MutexGuard
const guard( m_aMutex
);
1801 // container syncs with passed mutex ref
1802 maListenerContainer
.addInterface(xListener
);
1805 void SlideShowImpl::removeSlideShowListener(
1806 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1808 osl::MutexGuard
const guard( m_aMutex
);
1810 // container syncs with passed mutex ref
1811 maListenerContainer
.removeInterface(xListener
);
1814 void SlideShowImpl::addShapeEventListener(
1815 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1816 uno::Reference
<drawing::XShape
> const& xShape
)
1818 osl::MutexGuard
const guard( m_aMutex
);
1823 // precondition: must only be called from the main thread!
1824 DBG_TESTSOLARMUTEX();
1826 ShapeEventListenerMap::iterator aIter
;
1827 if( (aIter
=maShapeEventListeners
.find( xShape
)) ==
1828 maShapeEventListeners
.end() )
1830 // no entry for this shape -> create one
1831 aIter
= maShapeEventListeners
.emplace(
1833 std::make_shared
<comphelper::OInterfaceContainerHelper2
>(
1837 // add new listener to broadcaster
1838 if( aIter
->second
.get() )
1839 aIter
->second
->addInterface( xListener
);
1841 maEventMultiplexer
.notifyShapeListenerAdded(xListener
,
1845 void SlideShowImpl::removeShapeEventListener(
1846 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1847 uno::Reference
<drawing::XShape
> const& xShape
)
1849 osl::MutexGuard
const guard( m_aMutex
);
1851 // precondition: must only be called from the main thread!
1852 DBG_TESTSOLARMUTEX();
1854 ShapeEventListenerMap::iterator aIter
;
1855 if( (aIter
= maShapeEventListeners
.find( xShape
)) !=
1856 maShapeEventListeners
.end() )
1858 // entry for this shape found -> remove listener from
1861 aIter
->second
.get(),
1862 "SlideShowImpl::removeShapeEventListener(): "
1863 "listener map contains NULL broadcast helper" );
1865 aIter
->second
->removeInterface( xListener
);
1868 maEventMultiplexer
.notifyShapeListenerRemoved(xListener
,
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_QUERY_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 SAL_WARN( "slideshow", comphelper::anyToString( cppu::getCaughtException() ) );
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 occoured.
2317 This will be forewarded 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 //===== FrameSynchronization ==================================================
2350 FrameSynchronization::FrameSynchronization (const double nFrameDuration
)
2352 mnFrameDuration(nFrameDuration
),
2353 mnNextFrameTargetTime(0),
2359 void FrameSynchronization::MarkCurrentFrame()
2361 mnNextFrameTargetTime
= maTimer
.getElapsedTime() + mnFrameDuration
;
2364 void FrameSynchronization::Synchronize()
2368 // Do busy waiting for now.
2369 while (maTimer
.getElapsedTime() < mnNextFrameTargetTime
)
2376 void FrameSynchronization::Activate()
2381 void FrameSynchronization::Deactivate()
2388 namespace sdecl
= comphelper::service_decl
;
2389 const sdecl::ServiceDecl
slideShowDecl(
2390 sdecl::class_
<SlideShowImpl
>(),
2391 "com.sun.star.comp.presentation.SlideShow",
2392 "com.sun.star.presentation.SlideShow" );
2394 // The C shared lib entry points
2396 SAL_DLLPUBLIC_EXPORT
void* SAL_CALL
slideshow_component_getFactory( sal_Char
const* pImplName
,
2399 return sdecl::component_getFactoryHelper( pImplName
, {&slideShowDecl
} );
2402 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */