xref: /trunk/main/slideshow/source/engine/slideshowimpl.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 #include <canvas/debug.hxx>
28 #include <tools/diagnose_ex.h>
29 
30 #include <cppuhelper/basemutex.hxx>
31 #include <cppuhelper/compbase1.hxx>
32 #include <cppuhelper/factory.hxx>
33 #include <cppuhelper/implementationentry.hxx>
34 #include <cppuhelper/compbase2.hxx>
35 #include <cppuhelper/interfacecontainer.h>
36 #include <cppuhelper/exc_hlp.hxx>
37 
38 #include <comphelper/anytostring.hxx>
39 #include <comphelper/make_shared_from_uno.hxx>
40 #include <comphelper/scopeguard.hxx>
41 #include <comphelper/optional.hxx>
42 #include <comphelper/servicedecl.hxx>
43 #include <comphelper/namecontainer.hxx>
44 
45 #include <cppcanvas/spritecanvas.hxx>
46 #include <cppcanvas/vclfactory.hxx>
47 #include <cppcanvas/basegfxfactory.hxx>
48 
49 #include <tools/debug.hxx>
50 
51 #include <basegfx/point/b2dpoint.hxx>
52 #include <basegfx/polygon/b2dpolygon.hxx>
53 #include <basegfx/matrix/b2dhommatrix.hxx>
54 #include <basegfx/polygon/b2dpolygontools.hxx>
55 #include <basegfx/polygon/b2dpolypolygontools.hxx>
56 #include <basegfx/tools/canvastools.hxx>
57 
58 #include <vcl/font.hxx>
59 #include "rtl/ref.hxx"
60 
61 #include <com/sun/star/beans/XPropertySet.hpp>
62 #include <com/sun/star/util/XModifyListener.hpp>
63 #include <com/sun/star/util/XUpdatable.hpp>
64 #include <com/sun/star/awt/XPaintListener.hpp>
65 #include <com/sun/star/awt/SystemPointer.hpp>
66 #include <com/sun/star/animations/TransitionType.hpp>
67 #include <com/sun/star/animations/TransitionSubType.hpp>
68 #include <com/sun/star/presentation/XSlideShow.hpp>
69 #include <com/sun/star/presentation/XSlideShowListener.hpp>
70 #include <com/sun/star/lang/XServiceInfo.hpp>
71 #include <com/sun/star/lang/XServiceName.hpp>
72 #include <com/sun/star/lang/XComponent.hpp>
73 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
74 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
75 #include <com/sun/star/drawing/PointSequence.hpp>
76 #include <com/sun/star/drawing/XLayer.hpp>
77 #include <com/sun/star/drawing/XLayerSupplier.hpp>
78 #include <com/sun/star/drawing/XLayerManager.hpp>
79 #include <com/sun/star/container/XNameAccess.hpp>
80 
81 #include "com/sun/star/uno/Reference.hxx"
82 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
83 
84 #include "unoviewcontainer.hxx"
85 #include "transitionfactory.hxx"
86 #include "eventmultiplexer.hxx"
87 #include "usereventqueue.hxx"
88 #include "eventqueue.hxx"
89 #include "cursormanager.hxx"
90 #include "slideshowcontext.hxx"
91 #include "activitiesqueue.hxx"
92 #include "activitiesfactory.hxx"
93 #include "interruptabledelayevent.hxx"
94 #include "slide.hxx"
95 #include "shapemaps.hxx"
96 #include "slideview.hxx"
97 #include "tools.hxx"
98 #include "unoview.hxx"
99 #include "slidebitmap.hxx"
100 #include "rehearsetimingsactivity.hxx"
101 #include "waitsymbol.hxx"
102 #include "effectrewinder.hxx"
103 #include "framerate.hxx"
104 
105 #include <boost/noncopyable.hpp>
106 #include <boost/bind.hpp>
107 
108 #include <map>
109 #include <vector>
110 #include <iterator>
111 #include <string>
112 #include <algorithm>
113 #include <stdio.h>
114 #include <iostream>
115 
116 using namespace com::sun::star;
117 using namespace ::slideshow::internal;
118 
119 namespace {
120 
121 /** During animations the update() method tells its caller to call it as
122     soon as possible. This gives us more time to render the next frame and
123     still maintain a steady frame rate. This class is responsible for
124     synchronizing the display of new frames and thus keeping the frame rate
125     steady.
126 */
127 class FrameSynchronization
128 {
129 public:
130     /** Create new object with a predefined duration between two frames.
131         @param nFrameDuration
132             The preferred duration between the display of two frames in
133             seconds.
134     */
135     FrameSynchronization (const double nFrameDuration);
136 
137     /** Set the current time as the time at which the current frame is
138         displayed. From this the target time of the next frame is derived.
139     */
140     void MarkCurrentFrame (void);
141 
142     /** When there is time left until the next frame is due then wait.
143         Otherwise return without delay.
144     */
145     void Synchronize (void);
146 
147     /** Activate frame synchronization when an animation is active and
148         frames are to be displayed in a steady rate. While active
149         Synchronize() will wait until the frame duration time has passed.
150     */
151     void Activate (void);
152 
153     /** Deactivate frame synchronization when no animation is active and the
154         time between frames depends on user actions and other external
155         sources. While deactivated Synchronize() will return without delay.
156     */
157     void Deactivate (void);
158 
159     /** Return the current time of the timer. It is not synchronized with
160         any other timer so its absolute values are of no concern. Typically
161         used during debugging to measure durations.
162     */
163     double GetCurrentTime (void) const;
164 
165 private:
166     /** The timer that is used for synchronization is independent from the
167         one used by SlideShowImpl: it is not paused or modified by
168         animations.
169     */
170     canvas::tools::ElapsedTime maTimer;
171     /** Time between the display of frames. Enforced only when mbIsActive
172         is <TRUE/>.
173     */
174     const double mnFrameDuration;
175     /** Time (of maTimer) when the next frame shall be displayed.
176         Synchronize() will wait until this time.
177     */
178     double mnNextFrameTargetTime;
179     /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
180         it returns immediately.
181     */
182     bool mbIsActive;
183 };
184 
185 
186 
187 
188 /******************************************************************************
189 
190    SlideShowImpl
191 
192    This class encapsulates the slideshow presentation viewer.
193 
194    With an instance of this class, it is possible to statically
195    and dynamically show a presentation, as defined by the
196    constructor-provided draw model (represented by a sequence
197    of ::com::sun::star::drawing::XDrawPage objects).
198 
199    It is possible to show the presentation on multiple views
200    simultaneously (e.g. for a multi-monitor setup). Since this
201    class also relies on user interaction, the corresponding
202    XSlideShowView interface provides means to register some UI
203    event listeners (mostly borrowed from awt::XWindow interface).
204 
205    Since currently (mid 2004), AOO isn't very well suited to
206    multi-threaded rendering, this class relies on <em>very
207    frequent</em> external update() calls, which will render the
208    next frame of animations. This works as follows: after the
209    displaySlide() has been successfully called (which setup and
210    starts an actual slide show), the update() method must be
211    called until it returns false.
212    Effectively, this puts the burden of providing
213    concurrency to the clients of this class, which, as noted
214    above, is currently unavoidable with the current state of
215    affairs (I've actually tried threading here, but failed
216    miserably when using the VCL canvas as the render backend -
217    deadlocked).
218 
219  ******************************************************************************/
220 
221 typedef cppu::WeakComponentImplHelper1<presentation::XSlideShow> SlideShowImplBase;
222 
223 typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
224 
225 // Maps XDrawPage for annotations persistence
226 typedef ::std::map< ::com::sun::star::uno::Reference<
227                                     ::com::sun::star::drawing::XDrawPage>,
228                                     PolyPolygonVector>  PolygonMap;
229 
230 class SlideShowImpl : private cppu::BaseMutex,
231                       public CursorManager,
232                       public SlideShowImplBase
233 {
234 public:
235     explicit SlideShowImpl(
236         uno::Reference<uno::XComponentContext> const& xContext );
237 
238     /** Notify that the transition phase of the current slide
239         has ended.
240 
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.
247 
248         This method notifies the end of the first phase.
249 
250         @param bPaintSlide
251         When true, Slide::show() is passed a true as well, denoting
252         explicit paint of slide content. Pass false here, if e.g. a
253         slide transition has already rendered the initial slide image.
254     */
255     void notifySlideTransitionEnded( bool bPaintSlide );
256 
257     /** Notify that the shape animation phase of the current slide
258         has ended.
259 
260         The life of a slide has three phases: the transition
261         phase, when the previous slide vanishes, and the
262         current slide becomes visible, the shape animation
263         phase, when shape effects are running, and the phase
264         after the last shape animation has ended, but before
265         the next slide transition starts.
266 
267         This method notifies the end of the second phase.
268     */
269     void notifySlideAnimationsEnded();
270 
271     /** Notify that the slide has ended.
272 
273         The life of a slide has three phases: the transition
274         phase, when the previous slide vanishes, and the
275         current slide becomes visible, the shape animation
276         phase, when shape effects are running, and the phase
277         after the last shape animation has ended, but before
278         the next slide transition starts.
279 
280         This method notifies the end of the third phase.
281     */
282     void notifySlideEnded (const bool bReverse);
283 
284     /** Notification from eventmultiplexer that a hyperlink
285         has been clicked.
286     */
287     bool notifyHyperLinkClicked( rtl::OUString const& hyperLink );
288 
289     /** Notification from eventmultiplexer that an animation event has occurred.
290         This will be forwarded to all registered XSlideShowListener
291      */
292     bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
293 
294 private:
295     // XSlideShow:
296     virtual sal_Bool SAL_CALL nextEffect();
297     virtual sal_Bool SAL_CALL previousEffect();
298     virtual sal_Bool SAL_CALL startShapeActivity(
299         uno::Reference<drawing::XShape> const& xShape );
300     virtual sal_Bool SAL_CALL stopShapeActivity(
301         uno::Reference<drawing::XShape> const& xShape );
302     virtual sal_Bool SAL_CALL pause( sal_Bool bPauseShow );
303     virtual uno::Reference<drawing::XDrawPage> SAL_CALL getCurrentSlide();
304     virtual void SAL_CALL displaySlide(
305         uno::Reference<drawing::XDrawPage> const& xSlide,
306         uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
307         uno::Reference<animations::XAnimationNode> const& xRootNode,
308         uno::Sequence<beans::PropertyValue> const& rProperties );
309     virtual void SAL_CALL registerUserPaintPolygons( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xDocFactory );
310     virtual sal_Bool SAL_CALL setProperty(
311         beans::PropertyValue const& rProperty );
312     virtual sal_Bool SAL_CALL addView(
313         uno::Reference<presentation::XSlideShowView> const& xView );
314     virtual sal_Bool SAL_CALL removeView(
315         uno::Reference<presentation::XSlideShowView> const& xView );
316     virtual sal_Bool SAL_CALL update( double & nNextTimeout );
317     virtual void SAL_CALL addSlideShowListener(
318         uno::Reference<presentation::XSlideShowListener> const& xListener );
319     virtual void SAL_CALL removeSlideShowListener(
320         uno::Reference<presentation::XSlideShowListener> const& xListener );
321     virtual void SAL_CALL addShapeEventListener(
322         uno::Reference<presentation::XShapeEventListener> const& xListener,
323         uno::Reference<drawing::XShape> const& xShape );
324     virtual void SAL_CALL removeShapeEventListener(
325         uno::Reference<presentation::XShapeEventListener> const& xListener,
326         uno::Reference<drawing::XShape> const& xShape );
327     virtual void SAL_CALL setShapeCursor(
328         uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape );
329 
330 
331     // CursorManager
332     // -----------------------------------------------------------
333 
334     virtual bool requestCursor( sal_Int16 nCursorShape );
335     virtual void resetCursor();
336 
337     /** This is somewhat similar to displaySlide when called for the current
338         slide. It has been simplified to take advantage of that no slide
339         change takes place. Furthermore it does not show the slide
340         transition.
341     */
342     void redisplayCurrentSlide (void);
343 
344 protected:
345     // WeakComponentImplHelperBase
346     virtual void SAL_CALL disposing();
347 
isDisposed() const348     bool isDisposed() const
349     {
350         return (rBHelper.bDisposed || rBHelper.bInDispose);
351     }
352 
353 private:
354     struct SeparateListenerImpl; friend struct SeparateListenerImpl;
355     class PrefetchPropertiesFunc; friend class PrefetchPropertiesFunc;
356 
357     // Stop currently running show.
358     void stopShow();
359 
360     // Find a polygons vector in maPolygons (map)
361     PolygonMap::iterator findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage);
362 
363     // Creates a new slide.
364     SlideSharedPtr makeSlide(
365         uno::Reference<drawing::XDrawPage> const& xDrawPage,
366         uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
367         uno::Reference<animations::XAnimationNode> const& xRootNode );
368 
369     // Checks whether the given slide/animation node matches mpPrefetchSlide
matches(SlideSharedPtr const & pSlide,uno::Reference<drawing::XDrawPage> const & xSlide,uno::Reference<animations::XAnimationNode> const & xNode)370     static bool matches(
371         SlideSharedPtr const& pSlide,
372         uno::Reference<drawing::XDrawPage> const& xSlide,
373         uno::Reference<animations::XAnimationNode> const& xNode )
374     {
375         if (pSlide)
376             return (pSlide->getXDrawPage() == xSlide &&
377                     pSlide->getXAnimationNode() == xNode);
378         else
379             return (!xSlide.is() && !xNode.is());
380     }
381 
382     // Resets the current slide transition sound object with a new one:
383     SoundPlayerSharedPtr resetSlideTransitionSound(
384         uno::Any const& url = uno::Any(), bool bLoopSound = false );
385 
386     // stops the current slide transition sound
387     void stopSlideTransitionSound();
388 
389     /** Prepare a slide transition
390 
391         This method registers all necessary events and
392         activities for a slide transition.
393 
394         @return the slide change activity, or NULL for no transition effect
395     */
396     ActivitySharedPtr createSlideTransition(
397         const uno::Reference< drawing::XDrawPage >&    xDrawPage,
398         const SlideSharedPtr&                          rLeavingSlide,
399         const SlideSharedPtr&                          rEnteringSlide,
400         const EventSharedPtr&                          rTransitionEndEvent );
401 
402     /** Request/release the wait symbol. The wait symbol is displayed when
403         there are more requests then releases. Locking the wait symbol
404         helps to avoid intermediate repaints.
405 
406         Do not call this method directly. Use WaitSymbolLock instead.
407     */
408     void requestWaitSymbol (void);
409     void releaseWaitSymbol (void);
410 
411     class WaitSymbolLock {public:
WaitSymbolLock(SlideShowImpl & rSlideShowImpl)412         WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
413             { mrSlideShowImpl.requestWaitSymbol(); }
~WaitSymbolLock(void)414         ~WaitSymbolLock(void)
415             { mrSlideShowImpl.releaseWaitSymbol(); }
416     private: SlideShowImpl& mrSlideShowImpl;
417     };
418 
419 
420     // Filter requested cursor shape against hard slideshow cursors (wait, etc.)
421     sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
422 
423     /** This method is called asynchronously to finish the rewinding of an
424         effect to the previous slide that was initiated earlier.
425     */
426     void rewindEffectToPreviousSlide (void);
427 
428     // all registered views
429     UnoViewContainer                        maViewContainer;
430 
431     // all registered slide show listeners
432     cppu::OInterfaceContainerHelper         maListenerContainer;
433 
434     // map of vectors, containing all registered listeners for a shape
435     ShapeEventListenerMap                   maShapeEventListeners;
436     // map of sal_Int16 values, specifying the mouse cursor for every shape
437     ShapeCursorMap                          maShapeCursors;
438 
439     // map of vector of Polygons, containing polygons drawn on each slide.
440     PolygonMap                              maPolygons;
441 
442     boost::optional<RGBColor>               maUserPaintColor;
443 
444     double                                  maUserPaintStrokeWidth;
445 
446     // changed for the eraser project
447     boost::optional<bool>           maEraseAllInk;
448     boost::optional<bool>           maSwitchPenMode;
449     boost::optional<bool>           maSwitchEraserMode;
450     boost::optional<sal_Int32>          maEraseInk;
451     // end changed
452 
453     boost::shared_ptr<canvas::tools::ElapsedTime> mpPresTimer;
454     ScreenUpdater                           maScreenUpdater;
455     EventQueue                              maEventQueue;
456     EventMultiplexer                        maEventMultiplexer;
457     ActivitiesQueue                         maActivitiesQueue;
458     UserEventQueue                          maUserEventQueue;
459     SubsettableShapeManagerSharedPtr        mpDummyPtr;
460 
461     boost::shared_ptr<SeparateListenerImpl> mpListener;
462 
463     boost::shared_ptr<RehearseTimingsActivity> mpRehearseTimingsActivity;
464     boost::shared_ptr<WaitSymbol>           mpWaitSymbol;
465 
466     // the current slide transition sound object:
467     SoundPlayerSharedPtr                    mpCurrentSlideTransitionSound;
468 
469     uno::Reference<uno::XComponentContext>  mxComponentContext;
470     uno::Reference<
471         presentation::XTransitionFactory>   mxOptionalTransitionFactory;
472 
473     // the previously running slide
474     SlideSharedPtr                          mpPreviousSlide;
475     // the currently running slide
476     SlideSharedPtr                          mpCurrentSlide;
477     // the already prefetched slide: best candidate for upcoming slide
478     SlideSharedPtr                          mpPrefetchSlide;
479     // slide to be prefetched: best candidate for upcoming slide
480     uno::Reference<drawing::XDrawPage>      mxPrefetchSlide;
481     // save the XDrawPagesSupplier to retrieve polygons
482     uno::Reference<drawing::XDrawPagesSupplier>  mxDrawPagesSupplier;
483     // slide animation to be prefetched:
484     uno::Reference<animations::XAnimationNode> mxPrefetchAnimationNode;
485 
486     sal_Int16                               mnCurrentCursor;
487 
488     sal_Int32                               mnWaitSymbolRequestCount;
489     bool                                    mbAutomaticAdvancementMode;
490     bool                                    mbImageAnimationsAllowed;
491     bool                                    mbNoSlideTransitions;
492     bool                                    mbMouseVisible;
493     bool                                    mbForceManualAdvance;
494     bool                                    mbShowPaused;
495     bool                                    mbSlideShowIdle;
496     bool                                    mbDisableAnimationZOrder;
497 
498     EffectRewinder                          maEffectRewinder;
499     FrameSynchronization                    maFrameSynchronization;
500 };
501 
502 
503 /** Separate event listener for animation, view and hyperlink events.
504 
505     This handler is registered for slide animation end, view and
506     hyperlink events at the global EventMultiplexer, and forwards
507     notifications to the SlideShowImpl
508 */
509 struct SlideShowImpl::SeparateListenerImpl : public EventHandler,
510                                              public ViewRepaintHandler,
511                                              public HyperlinkHandler,
512                                              public AnimationEventHandler,
513                                              private boost::noncopyable
514 {
515     SlideShowImpl& mrShow;
516     ScreenUpdater& mrScreenUpdater;
517     EventQueue&    mrEventQueue;
518 
SeparateListenerImpl__anon857254e10111::SlideShowImpl::SeparateListenerImpl519     SeparateListenerImpl( SlideShowImpl& rShow,
520                           ScreenUpdater& rScreenUpdater,
521                           EventQueue&    rEventQueue ) :
522         mrShow( rShow ),
523         mrScreenUpdater( rScreenUpdater ),
524         mrEventQueue( rEventQueue )
525     {}
526 
527     // EventHandler
handleEvent__anon857254e10111::SlideShowImpl::SeparateListenerImpl528     virtual bool handleEvent()
529     {
530         // DON'T call notifySlideAnimationsEnded()
531         // directly, but queue an event. handleEvent()
532         // might be called from e.g.
533         // showNext(), and notifySlideAnimationsEnded() must not be called
534         // in recursion. Note that the event is scheduled for the next
535         // frame so that its expensive execution does not come in between
536         // sprite hiding and shape redraw (at the end of the animation of a
537         // shape), which would cause a flicker.
538         mrEventQueue.addEventForNextRound(
539             makeEvent(
540                 boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
541                 "SlideShowImpl::notifySlideAnimationsEnded"));
542         return true;
543     }
544 
545     // ViewRepaintHandler
viewClobbered__anon857254e10111::SlideShowImpl::SeparateListenerImpl546     virtual void viewClobbered( const UnoViewSharedPtr& rView )
547     {
548         // given view needs repaint, request update
549         mrScreenUpdater.notifyUpdate(rView, true);
550     }
551 
552     // HyperlinkHandler
handleHyperlink__anon857254e10111::SlideShowImpl::SeparateListenerImpl553     virtual bool handleHyperlink( ::rtl::OUString const& rLink )
554     {
555         return mrShow.notifyHyperLinkClicked(rLink);
556     }
557 
558     // AnimationEventHandler
handleAnimationEvent__anon857254e10111::SlideShowImpl::SeparateListenerImpl559     virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
560     {
561         return mrShow.handleAnimationEvent(rNode);
562     }
563 };
564 
565 
SlideShowImpl(uno::Reference<uno::XComponentContext> const & xContext)566 SlideShowImpl::SlideShowImpl(
567     uno::Reference<uno::XComponentContext> const& xContext )
568     : SlideShowImplBase(m_aMutex),
569       maViewContainer(),
570       maListenerContainer( m_aMutex ),
571       maShapeEventListeners(),
572       maShapeCursors(),
573       maUserPaintColor(),
574       maUserPaintStrokeWidth(4.0),
575       mpPresTimer( new canvas::tools::ElapsedTime ),
576       maScreenUpdater(maViewContainer),
577       maEventQueue( mpPresTimer ),
578       maEventMultiplexer( maEventQueue,
579                           maViewContainer ),
580       maActivitiesQueue( mpPresTimer ),
581       maUserEventQueue( maEventMultiplexer,
582                         maEventQueue,
583                         *this ),
584       mpDummyPtr(),
585       mpListener(),
586       mpRehearseTimingsActivity(),
587       mpWaitSymbol(),
588       mpCurrentSlideTransitionSound(),
589       mxComponentContext( xContext ),
590       mxOptionalTransitionFactory(),
591       mpCurrentSlide(),
592       mpPrefetchSlide(),
593       mxPrefetchSlide(),
594       mxDrawPagesSupplier(),
595       mxPrefetchAnimationNode(),
596       mnCurrentCursor(awt::SystemPointer::ARROW),
597       mnWaitSymbolRequestCount(0),
598       mbAutomaticAdvancementMode(false),
599       mbImageAnimationsAllowed( true ),
600       mbNoSlideTransitions( false ),
601       mbMouseVisible( true ),
602       mbForceManualAdvance( false ),
603       mbShowPaused( false ),
604       mbSlideShowIdle( true ),
605       mbDisableAnimationZOrder( false ),
606       maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue),
607       maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
608 
609 {
610     // keep care not constructing any UNO references to this inside ctor,
611     // shift that code to create()!
612 
613     uno::Reference<lang::XMultiComponentFactory> xFactory(
614         mxComponentContext->getServiceManager() );
615 
616     if( xFactory.is() )
617     {
618         try
619     {
620             // #i82460# try to retrieve special transition factory
621             mxOptionalTransitionFactory.set(
622                 xFactory->createInstanceWithContext(
623                     ::rtl::OUString::createFromAscii( "com.sun.star.presentation.TransitionFactory" ),
624                     mxComponentContext ),
625                 uno::UNO_QUERY );
626         }
627         catch (loader::CannotActivateFactoryException const&)
628     {
629     }
630     }
631 
632     mpListener.reset( new SeparateListenerImpl(
633                           *this,
634                           maScreenUpdater,
635                           maEventQueue ));
636     maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
637     maEventMultiplexer.addViewRepaintHandler( mpListener );
638     maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
639     maEventMultiplexer.addAnimationStartHandler( mpListener );
640     maEventMultiplexer.addAnimationEndHandler( mpListener );
641 }
642 
643 // we are about to be disposed (someone call dispose() on us)
disposing()644 void SlideShowImpl::disposing()
645 {
646     osl::MutexGuard const guard( m_aMutex );
647 
648     maEffectRewinder.dispose();
649 
650     // stop slide transition sound, if any:
651     stopSlideTransitionSound();
652 
653     mxComponentContext.clear();
654 
655     if( mpCurrentSlideTransitionSound )
656     {
657         mpCurrentSlideTransitionSound->dispose();
658         mpCurrentSlideTransitionSound.reset();
659     }
660 
661     mpWaitSymbol.reset();
662 
663     if( mpRehearseTimingsActivity )
664     {
665         mpRehearseTimingsActivity->dispose();
666         mpRehearseTimingsActivity.reset();
667     }
668 
669     if( mpListener )
670     {
671         maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
672         maEventMultiplexer.removeViewRepaintHandler(mpListener);
673         maEventMultiplexer.removeHyperlinkHandler(mpListener);
674         maEventMultiplexer.removeAnimationStartHandler( mpListener );
675         maEventMultiplexer.removeAnimationEndHandler( mpListener );
676 
677         mpListener.reset();
678     }
679 
680     maUserEventQueue.clear();
681     maActivitiesQueue.clear();
682     maEventMultiplexer.clear();
683     maEventQueue.clear();
684     mpPresTimer.reset();
685     maShapeCursors.clear();
686     maShapeEventListeners.clear();
687 
688     // send all listeners a disposing() that we are going down:
689     maListenerContainer.disposeAndClear(
690         lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
691 
692     maViewContainer.dispose();
693 
694     // release slides:
695     mxPrefetchAnimationNode.clear();
696     mxPrefetchSlide.clear();
697     mpPrefetchSlide.reset();
698     mpCurrentSlide.reset();
699     mpPreviousSlide.reset();
700 }
701 
702 // stops the current slide transition sound
stopSlideTransitionSound()703 void SlideShowImpl::stopSlideTransitionSound()
704 {
705     if (mpCurrentSlideTransitionSound)
706     {
707         mpCurrentSlideTransitionSound->stopPlayback();
708         mpCurrentSlideTransitionSound->dispose();
709         mpCurrentSlideTransitionSound.reset();
710     }
711  }
712 
resetSlideTransitionSound(const uno::Any & rSound,bool bLoopSound)713 SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
714 {
715     sal_Bool bStopSound = sal_False;
716     rtl::OUString url;
717 
718     if( !(rSound >>= bStopSound) )
719         bStopSound = sal_False;
720     rSound >>= url;
721 
722     if( !bStopSound && (url.getLength() == 0) )
723         return SoundPlayerSharedPtr();
724 
725     stopSlideTransitionSound();
726 
727     if (url.getLength() > 0)
728     {
729         try
730         {
731             mpCurrentSlideTransitionSound = SoundPlayer::create(
732                 maEventMultiplexer, url, mxComponentContext );
733             mpCurrentSlideTransitionSound->setPlaybackLoop( bLoopSound );
734         }
735         catch (lang::NoSupportException const&)
736         {
737             // catch possible exceptions from SoundPlayer, since
738             // being not able to playback the sound is not a hard
739             // error here (still, the slide transition should be
740             // shown).
741         }
742     }
743     return mpCurrentSlideTransitionSound;
744 }
745 
createSlideTransition(const uno::Reference<drawing::XDrawPage> & xDrawPage,const SlideSharedPtr & rLeavingSlide,const SlideSharedPtr & rEnteringSlide,const EventSharedPtr & rTransitionEndEvent)746 ActivitySharedPtr SlideShowImpl::createSlideTransition(
747     const uno::Reference< drawing::XDrawPage >& xDrawPage,
748     const SlideSharedPtr&                       rLeavingSlide,
749     const SlideSharedPtr&                       rEnteringSlide,
750     const EventSharedPtr&                       rTransitionEndEvent)
751 {
752     ENSURE_OR_THROW( !maViewContainer.empty(),
753                       "createSlideTransition(): No views" );
754     ENSURE_OR_THROW( rEnteringSlide,
755                       "createSlideTransition(): No entering slide" );
756 
757     // return empty transition, if slide transitions
758     // are disabled.
759     if (mbNoSlideTransitions)
760         return ActivitySharedPtr();
761 
762     // retrieve slide change parameters from XDrawPage
763     uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
764                                                     uno::UNO_QUERY );
765 
766     if( !xPropSet.is() )
767     {
768         OSL_TRACE( "createSlideTransition(): "
769                    "Slide has no PropertySet - assuming no transition\n" );
770         return ActivitySharedPtr();
771     }
772 
773     sal_Int16 nTransitionType(0);
774     if( !getPropertyValue( nTransitionType,
775                            xPropSet,
776                            OUSTR("TransitionType" )) )
777     {
778         OSL_TRACE( "createSlideTransition(): "
779                    "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
780         return ActivitySharedPtr();
781     }
782 
783     sal_Int16 nTransitionSubType(0);
784     if( !getPropertyValue( nTransitionSubType,
785                            xPropSet,
786                            OUSTR("TransitionSubtype" )) )
787     {
788         OSL_TRACE( "createSlideTransition(): "
789                    "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
790         return ActivitySharedPtr();
791     }
792 
793     bool bTransitionDirection(false);
794     if( !getPropertyValue( bTransitionDirection,
795                            xPropSet,
796                            OUSTR("TransitionDirection")) )
797     {
798         OSL_TRACE( "createSlideTransition(): "
799                    "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
800     }
801 
802     sal_Int32 aUnoColor(0);
803     if( !getPropertyValue( aUnoColor,
804                            xPropSet,
805                            OUSTR("TransitionFadeColor")) )
806     {
807         OSL_TRACE( "createSlideTransition(): "
808                    "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
809     }
810 
811     const RGBColor aTransitionFadeColor( unoColor2RGBColor( aUnoColor ));
812 
813     uno::Any aSound;
814     sal_Bool bLoopSound = sal_False;
815 
816     if( !getPropertyValue( aSound, xPropSet, OUSTR("Sound")) )
817         OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound\n" );
818 
819     if( !getPropertyValue( bLoopSound, xPropSet, OUSTR("LoopSound") ) )
820         OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound\n" );
821 
822     NumberAnimationSharedPtr pTransition(
823         TransitionFactory::createSlideTransition(
824             rLeavingSlide,
825             rEnteringSlide,
826             maViewContainer,
827             maScreenUpdater,
828             maEventMultiplexer,
829             mxOptionalTransitionFactory,
830             nTransitionType,
831             nTransitionSubType,
832             bTransitionDirection,
833             aTransitionFadeColor,
834             resetSlideTransitionSound( aSound, bLoopSound ) ));
835 
836     if( !pTransition )
837         return ActivitySharedPtr(); // no transition effect has been
838                                     // generated. Normally, that means
839                                     // that simply no transition is
840                                     // set on this slide.
841 
842     double nTransitionDuration(0.0);
843     if( !getPropertyValue( nTransitionDuration,
844                            xPropSet,
845                            OUSTR("TransitionDuration")) )
846     {
847         OSL_TRACE( "createSlideTransition(): "
848                    "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
849         return ActivitySharedPtr();
850     }
851 
852     sal_Int32 nMinFrames(5);
853     if( !getPropertyValue( nMinFrames,
854                            xPropSet,
855                            OUSTR("MinimalFrameNumber")) )
856     {
857         OSL_TRACE( "createSlideTransition(): "
858                    "No minimal number of frames given - assuming 5\n" );
859     }
860 
861     // prefetch slide transition bitmaps, but postpone it after
862     // displaySlide() has finished - sometimes, view size has not yet
863     // reached final size
864     maEventQueue.addEvent(
865         makeEvent(
866             boost::bind(
867                 &::slideshow::internal::Animation::prefetch,
868                 pTransition,
869                 AnimatableShapeSharedPtr(),
870                 ShapeAttributeLayerSharedPtr()),
871             "Animation::prefetch"));
872 
873     return ActivitySharedPtr(
874         ActivitiesFactory::createSimpleActivity(
875             ActivitiesFactory::CommonParameters(
876                 rTransitionEndEvent,
877                 maEventQueue,
878                 maActivitiesQueue,
879                 nTransitionDuration,
880                 nMinFrames,
881                 false,
882                 boost::optional<double>(1.0),
883                 0.0,
884                 0.0,
885                 ShapeSharedPtr(),
886                 rEnteringSlide->getSlideSize() ),
887             pTransition,
888             true ));
889 }
890 
findPolygons(uno::Reference<drawing::XDrawPage> const & xDrawPage)891 PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
892 {
893     // TODO(P2) : Optimize research in the map.
894     bool bFound = false;
895     PolygonMap::iterator aIter=maPolygons.begin();
896 
897 
898     while(aIter!=maPolygons.end() && !bFound)
899     {
900         if(aIter->first == xDrawPage)
901             bFound = true;
902         else
903             aIter++;
904     }
905 
906     return aIter;
907 }
908 
makeSlide(uno::Reference<drawing::XDrawPage> const & xDrawPage,uno::Reference<drawing::XDrawPagesSupplier> const & xDrawPages,uno::Reference<animations::XAnimationNode> const & xRootNode)909 SlideSharedPtr SlideShowImpl::makeSlide(
910     uno::Reference<drawing::XDrawPage> const&          xDrawPage,
911     uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
912     uno::Reference<animations::XAnimationNode> const&  xRootNode )
913 {
914     if( !xDrawPage.is() )
915         return SlideSharedPtr();
916 
917     // Retrieve polygons for the current slide
918     PolygonMap::iterator aIter;
919     aIter = findPolygons(xDrawPage);
920 
921     const SlideSharedPtr pSlide( createSlide(xDrawPage,
922                                              xDrawPages,
923                                              xRootNode,
924                                              maEventQueue,
925                                              maEventMultiplexer,
926                                              maScreenUpdater,
927                                              maActivitiesQueue,
928                                              maUserEventQueue,
929                                              *this,
930                                              maViewContainer,
931                                              mxComponentContext,
932                                              maShapeEventListeners,
933                                              maShapeCursors,
934                                              (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
935                                              maUserPaintColor ? *maUserPaintColor : RGBColor(),
936                                              maUserPaintStrokeWidth,
937                                              !!maUserPaintColor,
938                                              mbImageAnimationsAllowed,
939                                              mbDisableAnimationZOrder) );
940 
941     // prefetch show content (reducing latency for slide
942     // bitmap and effect start later on)
943     pSlide->prefetch();
944 
945     return pSlide;
946 }
947 
requestWaitSymbol(void)948 void SlideShowImpl::requestWaitSymbol (void)
949 {
950     ++mnWaitSymbolRequestCount;
951     OSL_ASSERT(mnWaitSymbolRequestCount>0);
952 
953     if (mnWaitSymbolRequestCount == 1)
954     {
955         if( !mpWaitSymbol )
956         {
957             // fall back to cursor
958             requestCursor(calcActiveCursor(mnCurrentCursor));
959         }
960         else
961             mpWaitSymbol->show();
962     }
963 }
964 
releaseWaitSymbol(void)965 void SlideShowImpl::releaseWaitSymbol (void)
966 {
967     --mnWaitSymbolRequestCount;
968     OSL_ASSERT(mnWaitSymbolRequestCount>=0);
969 
970     if (mnWaitSymbolRequestCount == 0)
971     {
972         if( !mpWaitSymbol )
973         {
974             // fall back to cursor
975             requestCursor(calcActiveCursor(mnCurrentCursor));
976         }
977         else
978             mpWaitSymbol->hide();
979     }
980 }
981 
calcActiveCursor(sal_Int16 nCursorShape) const982 sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
983 {
984     if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
985         nCursorShape = awt::SystemPointer::WAIT;
986     else if( !mbMouseVisible ) // enforce INVISIBLE
987         nCursorShape = awt::SystemPointer::INVISIBLE;
988     else if( maUserPaintColor &&
989              nCursorShape == awt::SystemPointer::ARROW )
990         nCursorShape = awt::SystemPointer::PEN;
991 
992     return nCursorShape;
993 }
994 
995 
stopShow()996 void SlideShowImpl::stopShow()
997 {
998     // Force-end running animation
999     // ===========================
1000     if (mpCurrentSlide)
1001     {
1002         mpCurrentSlide->hide();
1003         // Register polygons in the map
1004         if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1005             maPolygons.erase(mpCurrentSlide->getXDrawPage());
1006 
1007         maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1008     }
1009 
1010     // clear all queues
1011     maEventQueue.clear();
1012     maActivitiesQueue.clear();
1013 
1014     // Attention: we MUST clear the user event queue here,
1015     // this is because the current slide might have registered
1016     // shape events (click or enter/leave), which might
1017     // otherwise dangle forever in the queue (because of the
1018     // shared ptr nature). If someone needs to change this:
1019     // somehow unregister those shapes at the user event queue
1020     // on notifySlideEnded().
1021     maUserEventQueue.clear();
1022 
1023     // re-enable automatic effect advancement
1024     // (maEventQueue.clear() above might have killed
1025     // maEventMultiplexer's tick events)
1026     if (mbAutomaticAdvancementMode)
1027     {
1028         // toggle automatic mode (enabling just again is
1029         // ignored by EventMultiplexer)
1030         maEventMultiplexer.setAutomaticMode( false );
1031         maEventMultiplexer.setAutomaticMode( true );
1032     }
1033 }
1034 
1035 
1036 
1037 class SlideShowImpl::PrefetchPropertiesFunc
1038 {
1039 public:
PrefetchPropertiesFunc(SlideShowImpl * that_,bool & rbSkipAllMainSequenceEffects,bool & rbSkipSlideTransition)1040     PrefetchPropertiesFunc( SlideShowImpl * that_,
1041         bool& rbSkipAllMainSequenceEffects,
1042         bool& rbSkipSlideTransition)
1043         : mpSlideShowImpl(that_),
1044           mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
1045           mrbSkipSlideTransition(rbSkipSlideTransition)
1046     {}
1047 
operator ()(beans::PropertyValue const & rProperty) const1048     void operator()( beans::PropertyValue const& rProperty ) const {
1049         if (rProperty.Name.equalsAsciiL(
1050                 RTL_CONSTASCII_STRINGPARAM("Prefetch") ))
1051         {
1052             uno::Sequence<uno::Any> seq;
1053             if ((rProperty.Value >>= seq) && seq.getLength() == 2)
1054             {
1055                 seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
1056                 seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
1057             }
1058         }
1059         else if (rProperty.Name.equalsAsciiL(
1060                 RTL_CONSTASCII_STRINGPARAM("SkipAllMainSequenceEffects") ))
1061         {
1062             rProperty.Value >>= mrbSkipAllMainSequenceEffects;
1063         }
1064         else if (rProperty.Name.equalsAsciiL(
1065                 RTL_CONSTASCII_STRINGPARAM("SkipSlideTransition") ))
1066         {
1067             rProperty.Value >>= mrbSkipSlideTransition;
1068         }
1069         else
1070         {
1071             OSL_ENSURE( false, rtl::OUStringToOString(
1072                             rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1073         }
1074     }
1075 private:
1076     SlideShowImpl *const mpSlideShowImpl;
1077     bool& mrbSkipAllMainSequenceEffects;
1078     bool& mrbSkipSlideTransition;
1079 };
1080 
displaySlide(uno::Reference<drawing::XDrawPage> const & xSlide,uno::Reference<drawing::XDrawPagesSupplier> const & xDrawPages,uno::Reference<animations::XAnimationNode> const & xRootNode,uno::Sequence<beans::PropertyValue> const & rProperties)1081 void SlideShowImpl::displaySlide(
1082     uno::Reference<drawing::XDrawPage> const& xSlide,
1083     uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
1084     uno::Reference<animations::XAnimationNode> const& xRootNode,
1085     uno::Sequence<beans::PropertyValue> const& rProperties )
1086 {
1087     osl::MutexGuard const guard( m_aMutex );
1088 
1089     if (isDisposed())
1090         return;
1091 
1092     maEffectRewinder.setRootAnimationNode(xRootNode);
1093 
1094     // precondition: must only be called from the main thread!
1095     DBG_TESTSOLARMUTEX();
1096 
1097     mxDrawPagesSupplier = xDrawPages;
1098 
1099     stopShow(); // MUST call that: results in
1100     // maUserEventQueue.clear(). What's more,
1101     // stopShow()'s currSlide->hide() call is
1102     // now also required, notifySlideEnded()
1103     // relies on that
1104     // unconditionally. Otherwise, genuine
1105     // shape animations (drawing layer and
1106     // GIF) will not be stopped.
1107 
1108     bool bSkipAllMainSequenceEffects (false);
1109     bool bSkipSlideTransition (false);
1110     std::for_each( rProperties.getConstArray(),
1111                    rProperties.getConstArray() + rProperties.getLength(),
1112         PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
1113 
1114     OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1115     if (maViewContainer.empty())
1116         return;
1117 
1118     // this here might take some time
1119     {
1120         WaitSymbolLock aLock (*this);
1121 
1122         mpPreviousSlide = mpCurrentSlide;
1123         mpCurrentSlide.reset();
1124 
1125         if (matches( mpPrefetchSlide, xSlide, xRootNode ))
1126         {
1127             // prefetched slide matches:
1128             mpCurrentSlide = mpPrefetchSlide;
1129         }
1130         else
1131             mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
1132 
1133         OSL_ASSERT( mpCurrentSlide );
1134         if (mpCurrentSlide)
1135         {
1136             basegfx::B2DSize oldSlideSize;
1137             if( mpPreviousSlide )
1138                 oldSlideSize = mpPreviousSlide->getSlideSize();
1139 
1140             basegfx::B2DSize const slideSize( mpCurrentSlide->getSlideSize() );
1141 
1142             // push new transformation to all views, if size changed
1143             if( !mpPreviousSlide || oldSlideSize != slideSize )
1144             {
1145                 std::for_each( maViewContainer.begin(),
1146                                maViewContainer.end(),
1147                                boost::bind( &View::setViewSize, _1,
1148                                             boost::cref(slideSize) ));
1149 
1150                 // explicitly notify view change here,
1151                 // because transformation might have changed:
1152                 // optimization, this->notifyViewChange() would
1153                 // repaint slide which is not necessary.
1154                 maEventMultiplexer.notifyViewsChanged();
1155             }
1156 
1157             // create slide transition, and add proper end event
1158             // (which then starts the slide effects
1159             // via CURRENT_SLIDE.show())
1160             ActivitySharedPtr pSlideChangeActivity (
1161                 createSlideTransition(
1162                     mpCurrentSlide->getXDrawPage(),
1163                     mpPreviousSlide,
1164                     mpCurrentSlide,
1165                     makeEvent(
1166                         boost::bind(
1167                             &SlideShowImpl::notifySlideTransitionEnded,
1168                             this,
1169                             false ),
1170                         "SlideShowImpl::notifySlideTransitionEnded")));
1171 
1172             if (bSkipSlideTransition)
1173             {
1174                 // The transition activity was created for the side effects
1175                 // (like sound transitions). Because we want to skip the
1176                 // actual transition animation we do not need the activity
1177                 // anymore.
1178                 pSlideChangeActivity.reset();
1179             }
1180 
1181             if (pSlideChangeActivity)
1182             {
1183                 // factory generated a slide transition - activate it!
1184                 maActivitiesQueue.addActivity( pSlideChangeActivity );
1185             }
1186             else
1187             {
1188                 // no transition effect on this slide - schedule slide
1189                 // effect start event right away.
1190                 maEventQueue.addEvent(
1191                     makeEvent(
1192                         boost::bind(
1193                             &SlideShowImpl::notifySlideTransitionEnded,
1194                             this,
1195                             true ),
1196                         "SlideShowImpl::notifySlideTransitionEnded"));
1197             }
1198         }
1199     } // finally
1200 
1201     maEventMultiplexer.notifySlideTransitionStarted();
1202     maListenerContainer.forEach<presentation::XSlideShowListener>(
1203         boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1204 
1205     // We are currently rewinding an effect. This lead us from the next
1206     // slide to this one. To complete this we have to play back all main
1207     // sequence effects on this slide.
1208     if (bSkipAllMainSequenceEffects)
1209         maEffectRewinder.skipAllMainSequenceEffects();
1210 }
1211 
redisplayCurrentSlide(void)1212 void SlideShowImpl::redisplayCurrentSlide (void)
1213 {
1214     osl::MutexGuard const guard( m_aMutex );
1215 
1216     if (isDisposed())
1217         return;
1218 
1219     // precondition: must only be called from the main thread!
1220     DBG_TESTSOLARMUTEX();
1221     stopShow();
1222 
1223     OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1224     if (maViewContainer.empty())
1225         return;
1226 
1227     // No transition effect on this slide - schedule slide
1228     // effect start event right away.
1229     maEventQueue.addEvent(
1230         makeEvent(
1231             boost::bind(
1232                 &SlideShowImpl::notifySlideTransitionEnded,
1233                 this,
1234                 true ),
1235             "SlideShowImpl::notifySlideTransitionEnded"));
1236 
1237     maEventMultiplexer.notifySlideTransitionStarted();
1238     maListenerContainer.forEach<presentation::XSlideShowListener>(
1239         boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1240 }
1241 
nextEffect()1242 sal_Bool SlideShowImpl::nextEffect()
1243 {
1244     osl::MutexGuard const guard( m_aMutex );
1245 
1246     if (isDisposed())
1247         return false;
1248 
1249     // precondition: must only be called from the main thread!
1250     DBG_TESTSOLARMUTEX();
1251 
1252     if (mbShowPaused)
1253         return true;
1254     else
1255         return maEventMultiplexer.notifyNextEffect();
1256 }
1257 
1258 
previousEffect()1259 sal_Bool SlideShowImpl::previousEffect()
1260 {
1261     osl::MutexGuard const guard( m_aMutex );
1262 
1263     if (isDisposed())
1264         return false;
1265 
1266     // precondition: must only be called from the main thread!
1267     DBG_TESTSOLARMUTEX();
1268 
1269     if (mbShowPaused)
1270         return true;
1271     else
1272     {
1273         return maEffectRewinder.rewind(
1274             maScreenUpdater.createLock(false),
1275             ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
1276             ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
1277     }
1278 }
1279 
rewindEffectToPreviousSlide(void)1280 void SlideShowImpl::rewindEffectToPreviousSlide (void)
1281 {
1282     // Show the wait symbol now and prevent it from showing temporary slide
1283     // content while effects are played back.
1284     WaitSymbolLock aLock (*this);
1285 
1286     // A previous call to EffectRewinder::Rewind could not rewind the current
1287     // effect because there are no effects on the current slide or none has
1288     // yet been displayed. Go to the previous slide.
1289     notifySlideEnded(true);
1290 
1291     // Process pending events once more in order to have the following
1292     // screen update show the last effect. Not sure whether this should be
1293     // necessary.
1294     maEventQueue.forceEmpty();
1295 
1296     // We have to call the screen updater before the wait symbol is turned
1297     // off. Otherwise the wait symbol would force the display of an
1298     // intermediate state of the slide (before the effects are replayed.)
1299     maScreenUpdater.commitUpdates();
1300 }
1301 
startShapeActivity(uno::Reference<drawing::XShape> const &)1302 sal_Bool SlideShowImpl::startShapeActivity(
1303     uno::Reference<drawing::XShape> const& /*xShape*/ )
1304 {
1305     osl::MutexGuard const guard( m_aMutex );
1306 
1307     // precondition: must only be called from the main thread!
1308     DBG_TESTSOLARMUTEX();
1309 
1310     // TODO(F3): NYI
1311     OSL_ENSURE( false, "not yet implemented!" );
1312     return false;
1313 }
1314 
stopShapeActivity(uno::Reference<drawing::XShape> const &)1315 sal_Bool SlideShowImpl::stopShapeActivity(
1316     uno::Reference<drawing::XShape> const& /*xShape*/ )
1317 {
1318     osl::MutexGuard const guard( m_aMutex );
1319 
1320     // precondition: must only be called from the main thread!
1321     DBG_TESTSOLARMUTEX();
1322 
1323     // TODO(F3): NYI
1324     OSL_ENSURE( false, "not yet implemented!" );
1325     return false;
1326 }
1327 
pause(sal_Bool bPauseShow)1328 sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1329 {
1330     osl::MutexGuard const guard( m_aMutex );
1331 
1332     if (isDisposed())
1333         return false;
1334 
1335     // precondition: must only be called from the main thread!
1336     DBG_TESTSOLARMUTEX();
1337 
1338 
1339     if (bPauseShow)
1340         mpPresTimer->pauseTimer();
1341     else
1342         mpPresTimer->continueTimer();
1343 
1344     maEventMultiplexer.notifyPauseMode(bPauseShow);
1345 
1346     mbShowPaused = bPauseShow;
1347     return true;
1348 }
1349 
getCurrentSlide()1350 uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1351 {
1352     osl::MutexGuard const guard( m_aMutex );
1353 
1354     if (isDisposed())
1355         return uno::Reference<drawing::XDrawPage>();
1356 
1357     // precondition: must only be called from the main thread!
1358     DBG_TESTSOLARMUTEX();
1359 
1360     if (mpCurrentSlide)
1361         return mpCurrentSlide->getXDrawPage();
1362     else
1363         return uno::Reference<drawing::XDrawPage>();
1364 }
1365 
addView(uno::Reference<presentation::XSlideShowView> const & xView)1366 sal_Bool SlideShowImpl::addView(
1367     uno::Reference<presentation::XSlideShowView> const& xView )
1368 {
1369     osl::MutexGuard const guard( m_aMutex );
1370 
1371     if (isDisposed())
1372         return false;
1373 
1374     // precondition: must only be called from the main thread!
1375     DBG_TESTSOLARMUTEX();
1376 
1377     // first of all, check if view has a valid canvas
1378     ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
1379     ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
1380                        "addView(): View does not provide a valid canvas" );
1381 
1382     UnoViewSharedPtr const pView( createSlideView(
1383                                       xView,
1384                                       maEventQueue,
1385                                       maEventMultiplexer ));
1386     if (!maViewContainer.addView( pView ))
1387         return false; // view already added
1388 
1389     // initialize view content
1390     // =======================
1391 
1392     if (mpCurrentSlide)
1393     {
1394         // set view transformation
1395         const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
1396         pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
1397                                               slideSize.getY() ) );
1398     }
1399 
1400     // clear view area (since its newly added,
1401     // we need a clean slate)
1402     pView->clearAll();
1403 
1404     // broadcast newly added view
1405     maEventMultiplexer.notifyViewAdded( pView );
1406 
1407     // set current mouse ptr
1408     pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1409 
1410     return true;
1411 }
1412 
removeView(uno::Reference<presentation::XSlideShowView> const & xView)1413 sal_Bool SlideShowImpl::removeView(
1414     uno::Reference<presentation::XSlideShowView> const& xView )
1415 {
1416     osl::MutexGuard const guard( m_aMutex );
1417 
1418     // precondition: must only be called from the main thread!
1419     DBG_TESTSOLARMUTEX();
1420 
1421     ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
1422 
1423     UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
1424     if( !pView )
1425         return false; // view was not added in the first place
1426 
1427     // remove view from EventMultiplexer (mouse events etc.)
1428     maEventMultiplexer.notifyViewRemoved( pView );
1429 
1430     pView->_dispose();
1431 
1432     return true;
1433 }
1434 
registerUserPaintPolygons(const uno::Reference<lang::XMultiServiceFactory> & xDocFactory)1435 void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory )
1436 {
1437     // Retrieve Polygons if user ends presentation by context menu
1438     if (mpCurrentSlide)
1439     {
1440         if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1441             maPolygons.erase(mpCurrentSlide->getXDrawPage());
1442 
1443         maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1444     }
1445 
1446     // Creating the layer for shapes
1447     // query for the XLayerManager
1448     uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
1449     uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
1450 
1451     uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
1452     // create a layer and set its properties
1453     uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
1454     uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
1455 
1456     // Layer Name which enables to catch annotations
1457     rtl::OUString layerName = rtl::OUString::createFromAscii("DrawnInSlideshow");
1458     uno::Any aPropLayer;
1459 
1460     aPropLayer <<= layerName;
1461     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("Name"), aPropLayer);
1462 
1463     aPropLayer <<= true;
1464     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("IsVisible"), aPropLayer);
1465 
1466     aPropLayer <<= false;
1467     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("IsLocked"), aPropLayer);
1468 
1469     PolygonMap::iterator aIter=maPolygons.begin();
1470 
1471     PolyPolygonVector aPolygons;
1472     ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
1473     ::basegfx::B2DPolyPolygon b2DPolyPoly;
1474 
1475     // Register polygons for each slide
1476     while(aIter!=maPolygons.end())
1477     {
1478         aPolygons = aIter->second;
1479         // Get shapes for the slide
1480         ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > Shapes(aIter->first, ::com::sun::star::uno::UNO_QUERY);
1481         // Retrieve polygons for one slide
1482         for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
1483                  aEnd=aPolygons.end();
1484              aIterPoly!=aEnd; ++aIterPoly )
1485         {
1486             pPolyPoly = (*aIterPoly);
1487             b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
1488 
1489             // Normally there is only one polygon
1490             for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
1491             {
1492                 const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
1493                 sal_uInt32 nPoints = aPoly.count();
1494 
1495                 if( nPoints > 1)
1496                 {
1497                     // create the PolyLineShape
1498                     uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
1499                                                                     rtl::OUString::createFromAscii("com.sun.star.drawing.PolyLineShape") ) );
1500                     uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
1501 
1502                     // Add the shape to the slide
1503                     Shapes->add(rPolyShape);
1504 
1505                     // Retrieve shape properties
1506                     uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
1507                     // Construct a sequence of points sequence
1508                     drawing::PointSequenceSequence aRetval;
1509                     // Create only one sequence for one polygon
1510                     aRetval.realloc( 1 );
1511                     // Retrieve the sequence of points from aRetval
1512                     drawing::PointSequence* pOuterSequence = aRetval.getArray();
1513                     // Create 2 points in this sequence
1514                     pOuterSequence->realloc(nPoints);
1515                     // Get these points which are in an array
1516                     awt::Point* pInnerSequence = pOuterSequence->getArray();
1517                     for( sal_uInt32 n = 0; n < nPoints; n++ )
1518                     {
1519                         // Create a point from the polygon
1520                         *pInnerSequence++ = awt::Point(
1521                             basegfx::fround(aPoly.getB2DPoint(n).getX()),
1522                             basegfx::fround(aPoly.getB2DPoint(n).getY()));
1523                     }
1524 
1525                     // Fill the properties
1526                     // Give the built PointSequenceSequence.
1527                     uno::Any aParam;
1528                     aParam <<= aRetval;
1529                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("PolyPolygon"), aParam );
1530 
1531                     // LineStyle : SOLID by default
1532                     uno::Any            aAny;
1533                     drawing::LineStyle  eLS;
1534                     eLS = drawing::LineStyle_SOLID;
1535                     aAny <<= eLS;
1536                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineStyle"), aAny );
1537 
1538                     // LineColor
1539                     sal_uInt32          nLineColor;
1540                     nLineColor = pPolyPoly->getRGBALineColor();
1541                     // Transform polygon color from RRGGBBAA to AARRGGBB
1542                     aAny <<= RGBAColor2UnoColor(nLineColor);
1543                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineColor"), aAny );
1544 
1545                     // LineWidth
1546                     double              fLineWidth;
1547                     fLineWidth = pPolyPoly->getStrokeWidth();
1548                     aAny <<= (sal_Int32)fLineWidth;
1549                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineWidth"), aAny );
1550 
1551                     // make polygons special
1552                     xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1553                 }
1554             }
1555         }
1556         ++aIter;
1557     }
1558 }
1559 
setProperty(beans::PropertyValue const & rProperty)1560 sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1561 {
1562     osl::MutexGuard const guard( m_aMutex );
1563 
1564     if (isDisposed())
1565         return false;
1566 
1567     // precondition: must only be called from the main thread!
1568     DBG_TESTSOLARMUTEX();
1569 
1570     if (rProperty.Name.equalsAsciiL(
1571             RTL_CONSTASCII_STRINGPARAM("AutomaticAdvancement") ))
1572     {
1573         double nTimeout(0.0);
1574         mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
1575         if (mbAutomaticAdvancementMode)
1576         {
1577             maEventMultiplexer.setAutomaticTimeout( nTimeout );
1578         }
1579         maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
1580         return true;
1581     }
1582 
1583     if (rProperty.Name.equalsAsciiL(
1584             RTL_CONSTASCII_STRINGPARAM("UserPaintColor") ))
1585     {
1586         sal_Int32 nColor(0);
1587         if (rProperty.Value >>= nColor)
1588         {
1589             OSL_ENSURE( mbMouseVisible,
1590                         "setProperty(): User paint overrides invisible mouse" );
1591 
1592             // enable user paint
1593             maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
1594             if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
1595                 mpCurrentSlide->enablePaintOverlay();
1596 
1597             maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
1598         }
1599         else
1600         {
1601             // disable user paint
1602             maUserPaintColor.reset();
1603             maEventMultiplexer.notifyUserPaintDisabled();
1604             if( mpCurrentSlide )
1605                 mpCurrentSlide->disablePaintOverlay();
1606         }
1607 
1608         resetCursor();
1609 
1610         return true;
1611     }
1612 
1613     // adding support for erasing features in UserPaintOverlay
1614     if (rProperty.Name.equalsAsciiL(
1615             RTL_CONSTASCII_STRINGPARAM("EraseAllInk") ))
1616     {
1617         bool nEraseAllInk(false);
1618         if (rProperty.Value >>= nEraseAllInk)
1619         {
1620             OSL_ENSURE( mbMouseVisible,
1621                         "setProperty(): User paint overrides invisible mouse" );
1622 
1623             // enable user paint
1624             maEraseAllInk.reset( nEraseAllInk );
1625             maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
1626         }
1627 
1628         return true;
1629     }
1630 
1631     if (rProperty.Name.equalsAsciiL(
1632             RTL_CONSTASCII_STRINGPARAM("SwitchPenMode") ))
1633     {
1634         bool nSwitchPenMode(false);
1635         if (rProperty.Value >>= nSwitchPenMode)
1636         {
1637             OSL_ENSURE( mbMouseVisible,
1638                         "setProperty(): User paint overrides invisible mouse" );
1639 
1640             if(nSwitchPenMode == true){
1641             // Switch to Pen Mode
1642             maSwitchPenMode.reset( nSwitchPenMode );
1643             maEventMultiplexer.notifySwitchPenMode();
1644             }
1645         }
1646         return true;
1647     }
1648 
1649 
1650     if (rProperty.Name.equalsAsciiL(
1651             RTL_CONSTASCII_STRINGPARAM("SwitchEraserMode") ))
1652     {
1653         bool nSwitchEraserMode(false);
1654         if (rProperty.Value >>= nSwitchEraserMode)
1655         {
1656             OSL_ENSURE( mbMouseVisible,
1657                         "setProperty(): User paint overrides invisible mouse" );
1658             if(nSwitchEraserMode == true){
1659             // switch to Eraser mode
1660             maSwitchEraserMode.reset( nSwitchEraserMode );
1661             maEventMultiplexer.notifySwitchEraserMode();
1662             }
1663         }
1664 
1665         return true;
1666     }
1667 
1668 
1669 
1670     if (rProperty.Name.equalsAsciiL(
1671             RTL_CONSTASCII_STRINGPARAM("EraseInk") ))
1672     {
1673         sal_Int32 nEraseInk(100);
1674         if (rProperty.Value >>= nEraseInk)
1675         {
1676             OSL_ENSURE( mbMouseVisible,
1677                         "setProperty(): User paint overrides invisible mouse" );
1678 
1679             // enable user paint
1680             maEraseInk.reset( nEraseInk );
1681             maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
1682         }
1683 
1684         return true;
1685     }
1686 
1687     // new Property for pen's width
1688     if (rProperty.Name.equalsAsciiL(
1689             RTL_CONSTASCII_STRINGPARAM("UserPaintStrokeWidth") ))
1690     {
1691         double nWidth(4.0);
1692         if (rProperty.Value >>= nWidth)
1693         {
1694             OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
1695             // enable user paint stroke width
1696             maUserPaintStrokeWidth = nWidth;
1697             maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
1698         }
1699 
1700         return true;
1701     }
1702 
1703     if (rProperty.Name.equalsAsciiL(
1704             RTL_CONSTASCII_STRINGPARAM("AdvanceOnClick") ))
1705     {
1706         sal_Bool bAdvanceOnClick = sal_False;
1707         if (! (rProperty.Value >>= bAdvanceOnClick))
1708             return false;
1709         maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1710         return true;
1711     }
1712 
1713     if (rProperty.Name.equalsAsciiL(
1714             RTL_CONSTASCII_STRINGPARAM("DisableAnimationZOrder") ))
1715     {
1716         sal_Bool bDisableAnimationZOrder = sal_False;
1717         if (! (rProperty.Value >>= bDisableAnimationZOrder))
1718             return false;
1719         mbDisableAnimationZOrder = bDisableAnimationZOrder == sal_True;
1720         return true;
1721     }
1722 
1723     if (rProperty.Name.equalsAsciiL(
1724             RTL_CONSTASCII_STRINGPARAM("ImageAnimationsAllowed") ) )
1725     {
1726         if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1727             return false;
1728 
1729         // TODO(F3): Forward to slides!
1730 //         if( bOldValue != mbImageAnimationsAllowed )
1731 //         {
1732 //             if( mbImageAnimationsAllowed )
1733 //                 maEventMultiplexer.notifyIntrinsicAnimationsEnabled();
1734 //             else
1735 //                 maEventMultiplexer.notifyIntrinsicAnimationsDisabled();
1736 //         }
1737 
1738         return true;
1739     }
1740 
1741     if (rProperty.Name.equalsAsciiL(
1742             RTL_CONSTASCII_STRINGPARAM("MouseVisible") ))
1743     {
1744         if (! (rProperty.Value >>= mbMouseVisible))
1745             return false;
1746 
1747         requestCursor(mnCurrentCursor);
1748 
1749         return true;
1750     }
1751 
1752     if (rProperty.Name.equalsAsciiL(
1753             RTL_CONSTASCII_STRINGPARAM("ForceManualAdvance") ))
1754     {
1755         return (rProperty.Value >>= mbForceManualAdvance);
1756     }
1757 
1758     if (rProperty.Name.equalsAsciiL(
1759             RTL_CONSTASCII_STRINGPARAM("RehearseTimings") ))
1760     {
1761         bool bRehearseTimings = false;
1762         if (! (rProperty.Value >>= bRehearseTimings))
1763             return false;
1764 
1765         if (bRehearseTimings)
1766         {
1767             // TODO(Q3): Move to slide
1768             mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1769                 SlideShowContext(
1770                     mpDummyPtr,
1771                     maEventQueue,
1772                     maEventMultiplexer,
1773                     maScreenUpdater,
1774                     maActivitiesQueue,
1775                     maUserEventQueue,
1776                     *this,
1777                     maViewContainer,
1778                     mxComponentContext) );
1779         }
1780         else if (mpRehearseTimingsActivity)
1781         {
1782             // removes timer from all views:
1783             mpRehearseTimingsActivity->dispose();
1784             mpRehearseTimingsActivity.reset();
1785         }
1786         return true;
1787     }
1788 
1789     if (rProperty.Name.equalsAsciiL(
1790             RTL_CONSTASCII_STRINGPARAM("WaitSymbolBitmap") ))
1791     {
1792         uno::Reference<rendering::XBitmap> xBitmap;
1793         if (! (rProperty.Value >>= xBitmap))
1794             return false;
1795 
1796         mpWaitSymbol = WaitSymbol::create( xBitmap,
1797                                            maScreenUpdater,
1798                                            maEventMultiplexer,
1799                                            maViewContainer );
1800 
1801         return true;
1802     }
1803 
1804     if (rProperty.Name.equalsAsciiL(
1805             RTL_CONSTASCII_STRINGPARAM("NoSlideTransitions") ))
1806     {
1807         return (rProperty.Value >>= mbNoSlideTransitions);
1808     }
1809 
1810     if (rProperty.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("IsSoundEnabled")))
1811     {
1812         uno::Sequence<uno::Any> aValues;
1813         uno::Reference<presentation::XSlideShowView> xView;
1814         sal_Bool bValue (false);
1815         if ((rProperty.Value >>= aValues)
1816             && aValues.getLength()==2
1817             && (aValues[0] >>= xView)
1818             && (aValues[1] >>= bValue))
1819         {
1820             // Look up the view.
1821             for (UnoViewVector::const_iterator
1822                      iView (maViewContainer.begin()),
1823                      iEnd (maViewContainer.end());
1824                  iView!=iEnd;
1825                  ++iView)
1826             {
1827                 if (*iView && (*iView)->getUnoView()==xView)
1828                 {
1829                     // Store the flag at the view so that media shapes have
1830                     // access to it.
1831                     (*iView)->setIsSoundEnabled(bValue);
1832                     return true;
1833                 }
1834             }
1835         }
1836     }
1837 
1838     return false;
1839 }
1840 
addSlideShowListener(uno::Reference<presentation::XSlideShowListener> const & xListener)1841 void SlideShowImpl::addSlideShowListener(
1842     uno::Reference<presentation::XSlideShowListener> const& xListener )
1843 {
1844     osl::MutexGuard const guard( m_aMutex );
1845 
1846     if (isDisposed())
1847         return;
1848 
1849     // container syncs with passed mutex ref
1850     maListenerContainer.addInterface(xListener);
1851 }
1852 
removeSlideShowListener(uno::Reference<presentation::XSlideShowListener> const & xListener)1853 void SlideShowImpl::removeSlideShowListener(
1854     uno::Reference<presentation::XSlideShowListener> const& xListener )
1855 {
1856     osl::MutexGuard const guard( m_aMutex );
1857 
1858     // container syncs with passed mutex ref
1859     maListenerContainer.removeInterface(xListener);
1860 }
1861 
addShapeEventListener(uno::Reference<presentation::XShapeEventListener> const & xListener,uno::Reference<drawing::XShape> const & xShape)1862 void SlideShowImpl::addShapeEventListener(
1863     uno::Reference<presentation::XShapeEventListener> const& xListener,
1864     uno::Reference<drawing::XShape> const& xShape )
1865 {
1866     osl::MutexGuard const guard( m_aMutex );
1867 
1868     if (isDisposed())
1869         return;
1870 
1871     // precondition: must only be called from the main thread!
1872     DBG_TESTSOLARMUTEX();
1873 
1874     ShapeEventListenerMap::iterator aIter;
1875     if( (aIter=maShapeEventListeners.find( xShape )) ==
1876         maShapeEventListeners.end() )
1877     {
1878         // no entry for this shape -> create one
1879         aIter = maShapeEventListeners.insert(
1880             ShapeEventListenerMap::value_type(
1881                 xShape,
1882                 boost::shared_ptr<cppu::OInterfaceContainerHelper>(
1883                     new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
1884     }
1885 
1886     // add new listener to broadcaster
1887     if( aIter->second.get() )
1888         aIter->second->addInterface( xListener );
1889 
1890     maEventMultiplexer.notifyShapeListenerAdded(xListener,
1891                                                 xShape);
1892 }
1893 
removeShapeEventListener(uno::Reference<presentation::XShapeEventListener> const & xListener,uno::Reference<drawing::XShape> const & xShape)1894 void SlideShowImpl::removeShapeEventListener(
1895     uno::Reference<presentation::XShapeEventListener> const& xListener,
1896     uno::Reference<drawing::XShape> const& xShape )
1897 {
1898     osl::MutexGuard const guard( m_aMutex );
1899 
1900     // precondition: must only be called from the main thread!
1901     DBG_TESTSOLARMUTEX();
1902 
1903     ShapeEventListenerMap::iterator aIter;
1904     if( (aIter = maShapeEventListeners.find( xShape )) !=
1905         maShapeEventListeners.end() )
1906     {
1907         // entry for this shape found -> remove listener from
1908         // helper object
1909         ENSURE_OR_THROW(
1910             aIter->second.get(),
1911             "SlideShowImpl::removeShapeEventListener(): "
1912             "listener map contains NULL broadcast helper" );
1913 
1914         aIter->second->removeInterface( xListener );
1915     }
1916 
1917     maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1918                                                   xShape);
1919 }
1920 
setShapeCursor(uno::Reference<drawing::XShape> const & xShape,sal_Int16 nPointerShape)1921 void SlideShowImpl::setShapeCursor(
1922     uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
1923 {
1924     osl::MutexGuard const guard( m_aMutex );
1925 
1926     if (isDisposed())
1927         return;
1928 
1929     // precondition: must only be called from the main thread!
1930     DBG_TESTSOLARMUTEX();
1931 
1932     ShapeCursorMap::iterator aIter;
1933     if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
1934     {
1935         // no entry for this shape -> create one
1936         if( nPointerShape != awt::SystemPointer::ARROW )
1937         {
1938             // add new entry, unless shape shall display
1939             // normal pointer arrow -> no need to handle that
1940             // case
1941             maShapeCursors.insert(
1942                 ShapeCursorMap::value_type(xShape,
1943                                            nPointerShape) );
1944         }
1945     }
1946     else if( nPointerShape == awt::SystemPointer::ARROW )
1947     {
1948         // shape shall display normal cursor -> can disable
1949         // the cursor and clear the entry
1950         maShapeCursors.erase( xShape );
1951     }
1952     else
1953     {
1954         // existing entry found, update with new cursor ID
1955         aIter->second = nPointerShape;
1956     }
1957 
1958     maEventMultiplexer.notifyShapeCursorChange(xShape,
1959                                                nPointerShape);
1960 }
1961 
requestCursor(sal_Int16 nCursorShape)1962 bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
1963 {
1964     mnCurrentCursor = nCursorShape;
1965 
1966     const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
1967 
1968     // change all views to the requested cursor ID
1969     std::for_each( maViewContainer.begin(),
1970                    maViewContainer.end(),
1971                    boost::bind( &View::setCursorShape,
1972                                 _1,
1973                                 nActualCursor ));
1974 
1975     return nActualCursor==nCursorShape;
1976 }
1977 
resetCursor()1978 void SlideShowImpl::resetCursor()
1979 {
1980     mnCurrentCursor = awt::SystemPointer::ARROW;
1981 
1982     // change all views to the default cursor ID
1983     std::for_each( maViewContainer.begin(),
1984                    maViewContainer.end(),
1985                    boost::bind( &View::setCursorShape,
1986                                 _1,
1987                                 calcActiveCursor(mnCurrentCursor) ));
1988 }
1989 
update(double & nNextTimeout)1990 sal_Bool SlideShowImpl::update( double & nNextTimeout )
1991 {
1992     osl::MutexGuard const guard( m_aMutex );
1993 
1994     if (isDisposed())
1995         return false;
1996 
1997     // precondition: update() must only be called from the
1998     // main thread!
1999     DBG_TESTSOLARMUTEX();
2000 
2001     if( mbShowPaused )
2002     {
2003         // commit frame (might be repaints pending)
2004         maScreenUpdater.commitUpdates();
2005 
2006         return false;
2007     }
2008     else
2009     {
2010         // TODO(F2): re-evaluate whether that timer lagging makes
2011         // sense.
2012 
2013         // hold timer, while processing the queues:
2014         // 1. when there is more than one active activity this ensures the
2015         //    same time for all activities and events
2016         // 2. processing of events may lead to creation of further events
2017         //    that have zero delay. While the timer is stopped these events
2018         //    are processed in the same run.
2019         {
2020             comphelper::ScopeGuard scopeGuard(
2021                 boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
2022                              boost::cref(mpPresTimer) ) );
2023             mpPresTimer->holdTimer();
2024 
2025             // process queues
2026             maEventQueue.process();
2027 
2028             // #118671# the call above may execute a macro bound to an object. In
2029             // that case this macro may have destroyed this local slideshow so that it
2030             // is disposed (see bugdoc at task). In that case, detect this and exit
2031             // gently from this slideshow. Do not forget to disable the scoped
2032             // call to mpPresTimer, this will be deleted if we are disposed.
2033             if (isDisposed())
2034             {
2035                 scopeGuard.dismiss();
2036                 return false;
2037             }
2038 
2039             maActivitiesQueue.process();
2040 
2041             // commit frame to screen
2042             maFrameSynchronization.Synchronize();
2043             maScreenUpdater.commitUpdates();
2044 
2045             // TODO(Q3): remove need to call dequeued() from
2046             // activities. feels like a wart.
2047             //
2048             // Rationale for ActivitiesQueue::processDequeued(): when
2049             // an activity ends, it usually pushed the end state to
2050             // the animated shape in question, and ends the animation
2051             // (which, in turn, will usually disable shape sprite
2052             // mode). Disabling shape sprite mode causes shape
2053             // repaint, which, depending on slide content, takes
2054             // considerably more time than sprite updates. Thus, the
2055             // last animation step tends to look delayed. To
2056             // camouflage this, reaching end position and disabling
2057             // sprite mode is split into two (normal Activity::end(),
2058             // and Activity::dequeued()). Now, the reason to call
2059             // commitUpdates() twice here is caused by the unrelated
2060             // fact that during wait cursor display/hide, the screen
2061             // is updated, and shows hidden sprites, but, in case of
2062             // leaving the second commitUpdates() call out and punting
2063             // that to the next round, no updated static slide
2064             // content. In short, the last shape animation of a slide
2065             // tends to blink at its end.
2066 
2067             // process dequeued activities _after_ commit to screen
2068             maActivitiesQueue.processDequeued();
2069 
2070             // commit frame to screen
2071             maScreenUpdater.commitUpdates();
2072         }
2073         // Time held until here
2074 
2075         const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
2076         const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
2077         const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
2078 
2079         if (bRet)
2080         {
2081             // calc nNextTimeout value:
2082             if (bActivitiesLeft)
2083             {
2084                 // Activity queue is not empty. Tell caller that we would
2085                 // like to render another frame.
2086 
2087                 // Return a zero time-out to signal our caller to call us
2088                 // back as soon as possible. The actual timing, waiting the
2089                 // appropriate amount of time between frames, is then done
2090                 // by the maFrameSynchronization object.
2091                 nNextTimeout = 0;
2092                 maFrameSynchronization.Activate();
2093             }
2094             else
2095             {
2096                 // timer events left:
2097                 // difference from current time (nota bene:
2098                 // time no longer held here!) to the next event in
2099                 // the event queue.
2100 
2101                 // #i61190# Retrieve next timeout only _after_
2102                 // processing activity queue
2103 
2104                 // ensure positive value:
2105                 nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
2106 
2107                 // There is no active animation so the frame rate does not
2108                 // need to be synchronized.
2109                 maFrameSynchronization.Deactivate();
2110             }
2111 
2112             mbSlideShowIdle = false;
2113         }
2114 
2115 #if defined(VERBOSE) && defined(DBG_UTIL)
2116         // when slideshow is idle, issue an XUpdatable::update() call
2117         // exactly once after a previous animation sequence finished -
2118         // this might trigger screen dumps on some canvas
2119         // implementations
2120         if( !mbSlideShowIdle &&
2121             (!bRet ||
2122              nNextTimeout > 1.0) )
2123         {
2124             UnoViewVector::const_iterator       aCurr(maViewContainer.begin());
2125             const UnoViewVector::const_iterator aEnd(maViewContainer.end());
2126             while( aCurr != aEnd )
2127             {
2128                 try
2129                 {
2130                     uno::Reference< presentation::XSlideShowView > xView( (*aCurr)->getUnoView(),
2131                                                                           uno::UNO_QUERY_THROW );
2132                     uno::Reference< util::XUpdatable >             xUpdatable( xView->getCanvas(),
2133                                                                                uno::UNO_QUERY_THROW );
2134                     xUpdatable->update();
2135                 }
2136                 catch( uno::RuntimeException& )
2137                 {
2138                     throw;
2139                 }
2140                 catch( uno::Exception& )
2141                 {
2142                     OSL_ENSURE( false,
2143                                 rtl::OUStringToOString(
2144                                     comphelper::anyToString( cppu::getCaughtException() ),
2145                                     RTL_TEXTENCODING_UTF8 ).getStr() );
2146                 }
2147 
2148                 ++aCurr;
2149             }
2150 
2151             mbSlideShowIdle = true;
2152         }
2153 #endif
2154 
2155         return bRet;
2156     }
2157 }
2158 
notifySlideTransitionEnded(bool bPaintSlide)2159 void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
2160 {
2161     osl::MutexGuard const guard( m_aMutex );
2162 
2163     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2164     OSL_ENSURE( mpCurrentSlide,
2165                 "notifySlideTransitionEnded(): Invalid current slide" );
2166     if (mpCurrentSlide)
2167     {
2168         mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
2169 
2170         // first init show, to give the animations
2171         // the chance to register SlideStartEvents
2172         const bool bBackgroundLayerRendered( !bPaintSlide );
2173         mpCurrentSlide->show( bBackgroundLayerRendered );
2174         maEventMultiplexer.notifySlideStartEvent();
2175     }
2176 }
2177 
queryAutomaticSlideTransition(uno::Reference<drawing::XDrawPage> const & xDrawPage,double & nAutomaticNextSlideTimeout,bool & bHasAutomaticNextSlide)2178 void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
2179                                     double&                                   nAutomaticNextSlideTimeout,
2180                                     bool&                                     bHasAutomaticNextSlide )
2181 {
2182     // retrieve slide change parameters from XDrawPage
2183     // ===============================================
2184 
2185     uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
2186                                                     uno::UNO_QUERY );
2187 
2188     sal_Int32 nChange(0);
2189     if( !xPropSet.is() ||
2190         !getPropertyValue( nChange,
2191                            xPropSet,
2192                            ::rtl::OUString(
2193                                RTL_CONSTASCII_USTRINGPARAM("Change"))) )
2194     {
2195         OSL_TRACE(
2196             "queryAutomaticSlideTransition(): "
2197             "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2198     }
2199 
2200     bHasAutomaticNextSlide = nChange == 1;
2201 
2202     if( !xPropSet.is() ||
2203         !getPropertyValue( nAutomaticNextSlideTimeout,
2204                            xPropSet,
2205                            ::rtl::OUString(
2206                                RTL_CONSTASCII_USTRINGPARAM("Duration"))) )
2207     {
2208         OSL_TRACE(
2209             "queryAutomaticSlideTransition(): "
2210             "Could not extract slide transition timeout from "
2211             "XDrawPage - assuming 1 sec\n" );
2212     }
2213 }
2214 
notifySlideAnimationsEnded()2215 void SlideShowImpl::notifySlideAnimationsEnded()
2216 {
2217     osl::MutexGuard const guard( m_aMutex );
2218 
2219     // Draw polygons above animations
2220     mpCurrentSlide->drawPolygons();
2221 
2222     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2223 
2224     // This struct will receive the (interruptible) event,
2225     // that triggers the notifySlideEnded() method.
2226     InterruptableEventPair aNotificationEvents;
2227 
2228     if( maEventMultiplexer.getAutomaticMode() )
2229     {
2230         OSL_ENSURE( ! mpRehearseTimingsActivity,
2231                     "unexpected: RehearseTimings mode!" );
2232 
2233         // schedule a slide end event, with automatic mode's
2234         // delay
2235         aNotificationEvents = makeInterruptableDelay(
2236             boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2237             maEventMultiplexer.getAutomaticTimeout() );
2238     }
2239     else
2240     {
2241         OSL_ENSURE( mpCurrentSlide,
2242                     "notifySlideAnimationsEnded(): Invalid current slide!" );
2243 
2244         bool   bHasAutomaticNextSlide=false;
2245         double nAutomaticNextSlideTimeout=0.0;
2246         queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
2247                                       nAutomaticNextSlideTimeout,
2248                                       bHasAutomaticNextSlide);
2249 
2250         // check whether slide transition should happen
2251         // 'automatically'. If yes, simply schedule the
2252         // specified timeout.
2253         // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2254         // override any individual slide setting, to always
2255         // step slides manually.
2256         if( !mbForceManualAdvance &&
2257             !mpRehearseTimingsActivity &&
2258             bHasAutomaticNextSlide )
2259         {
2260             aNotificationEvents = makeInterruptableDelay(
2261                 boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2262                 nAutomaticNextSlideTimeout);
2263 
2264             // TODO(F2): Provide a mechanism to let the user override
2265             // this automatic timeout via next()
2266         }
2267         else
2268         {
2269             if (mpRehearseTimingsActivity)
2270                 mpRehearseTimingsActivity->start();
2271 
2272             // generate click event. Thus, the user must
2273             // trigger the actual end of a slide. No need to
2274             // generate interruptible event here, there's no
2275             // timeout involved.
2276             aNotificationEvents.mpImmediateEvent =
2277                 makeEvent( boost::bind<void>(
2278                     boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2279                     "SlideShowImpl::notifySlideEnded");
2280         }
2281     }
2282 
2283     // register events on the queues. To make automatic slide
2284     // changes interruptible, register the interruption event
2285     // as a nextEffectEvent target. Note that the timeout
2286     // event is optional (e.g. manual slide changes don't
2287     // generate a timeout)
2288     maUserEventQueue.registerNextEffectEvent(
2289         aNotificationEvents.mpImmediateEvent );
2290 
2291     if( aNotificationEvents.mpTimeoutEvent )
2292         maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
2293 
2294     // current slide's main sequence is over. Now should be
2295     // the time to prefetch the next slide (if any), and
2296     // prepare the initial slide bitmap (speeds up slide
2297     // change setup time a lot). Show the wait cursor, this
2298     // indeed might take some seconds.
2299     {
2300         WaitSymbolLock aLock (*this);
2301 
2302         if (! matches( mpPrefetchSlide,
2303                        mxPrefetchSlide, mxPrefetchAnimationNode ))
2304         {
2305             mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
2306                                          mxPrefetchAnimationNode );
2307         }
2308         if (mpPrefetchSlide)
2309         {
2310             // ignore return value, this is just to populate
2311             // Slide's internal bitmap buffer, such that the time
2312             // needed to generate the slide bitmap is not spent
2313             // when the slide change is requested.
2314             mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
2315         }
2316     } // finally
2317 
2318     maListenerContainer.forEach<presentation::XSlideShowListener>(
2319         boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
2320 }
2321 
notifySlideEnded(const bool bReverse)2322 void SlideShowImpl::notifySlideEnded (const bool bReverse)
2323 {
2324     osl::MutexGuard const guard( m_aMutex );
2325 
2326     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2327 
2328     if (mpRehearseTimingsActivity && !bReverse)
2329     {
2330         const double time = mpRehearseTimingsActivity->stop();
2331         if (mpRehearseTimingsActivity->hasBeenClicked())
2332         {
2333             // save time at current drawpage:
2334             uno::Reference<beans::XPropertySet> xPropSet(
2335                 mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
2336             OSL_ASSERT( xPropSet.is() );
2337             if (xPropSet.is())
2338             {
2339                 xPropSet->setPropertyValue(
2340                     OUSTR("Change"),
2341                     uno::Any( static_cast<sal_Int32>(1) ) );
2342                 xPropSet->setPropertyValue(
2343                     OUSTR("Duration"),
2344                     uno::Any( static_cast<sal_Int32>(time) ) );
2345             }
2346         }
2347     }
2348 
2349     if (bReverse)
2350         maEventMultiplexer.notifySlideEndEvent();
2351 
2352     stopShow();  // MUST call that: results in
2353                  // maUserEventQueue.clear(). What's more,
2354                  // stopShow()'s currSlide->hide() call is
2355                  // now also required, notifySlideEnded()
2356                  // relies on that
2357                  // unconditionally. Otherwise, genuine
2358                  // shape animations (drawing layer and
2359                  // GIF) will not be stopped.
2360 
2361     maListenerContainer.forEach<presentation::XSlideShowListener>(
2362         boost::bind<void>(
2363             ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2364             _1,
2365             sal_Bool(bReverse)));
2366 }
2367 
notifyHyperLinkClicked(rtl::OUString const & hyperLink)2368 bool SlideShowImpl::notifyHyperLinkClicked( rtl::OUString const& hyperLink )
2369 {
2370     osl::MutexGuard const guard( m_aMutex );
2371 
2372     maListenerContainer.forEach<presentation::XSlideShowListener>(
2373         boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
2374                      _1,
2375                      boost::cref(hyperLink) ));
2376     return true;
2377 }
2378 
2379 /** Notification from eventmultiplexer that an animation event has occurred.
2380     This will be forwarded to all registered XSlideShowListener
2381  */
handleAnimationEvent(const AnimationNodeSharedPtr & rNode)2382 bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
2383 {
2384     osl::MutexGuard const guard( m_aMutex );
2385 
2386     uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
2387 
2388     switch( rNode->getState() )
2389     {
2390     case AnimationNode::ACTIVE:
2391         maListenerContainer.forEach<presentation::XSlideShowListener>(
2392             boost::bind( &animations::XAnimationListener::beginEvent,
2393                          _1,
2394                          boost::cref(xNode) ));
2395         break;
2396 
2397     case AnimationNode::FROZEN:
2398     case AnimationNode::ENDED:
2399         maListenerContainer.forEach<presentation::XSlideShowListener>(
2400             boost::bind( &animations::XAnimationListener::endEvent,
2401                          _1,
2402                          boost::cref(xNode) ));
2403         if(mpCurrentSlide->isPaintOverlayActive())
2404            mpCurrentSlide->drawPolygons();
2405         break;
2406     default:
2407         break;
2408     }
2409 
2410     return true;
2411 }
2412 
2413 
2414 // ===== FrameSynchronization ==================================================
2415 
FrameSynchronization(const double nFrameDuration)2416 FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2417     : maTimer(),
2418       mnFrameDuration(nFrameDuration),
2419       mnNextFrameTargetTime(0),
2420       mbIsActive(false)
2421 {
2422     MarkCurrentFrame();
2423 }
2424 
2425 
2426 
2427 
MarkCurrentFrame(void)2428 void FrameSynchronization::MarkCurrentFrame (void)
2429 {
2430     mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2431 }
2432 
2433 
2434 
2435 
Synchronize(void)2436 void FrameSynchronization::Synchronize (void)
2437 {
2438     if (mbIsActive)
2439     {
2440         // Do busy waiting for now.
2441         while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2442             ;
2443     }
2444 
2445     MarkCurrentFrame();
2446 }
2447 
2448 
2449 
2450 
Activate(void)2451 void FrameSynchronization::Activate (void)
2452 {
2453     mbIsActive = true;
2454 }
2455 
2456 
2457 
2458 
Deactivate(void)2459 void FrameSynchronization::Deactivate (void)
2460 {
2461     mbIsActive = false;
2462 }
2463 
2464 
2465 
2466 
GetCurrentTime(void) const2467 double FrameSynchronization::GetCurrentTime (void) const
2468 {
2469     return maTimer.getElapsedTime();
2470 }
2471 
2472 
2473 } // anon namespace
2474 
2475 namespace sdecl = comphelper::service_decl;
2476 #if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
2477  sdecl::class_<SlideShowImpl> serviceImpl;
2478  const sdecl::ServiceDecl slideShowDecl(
2479      serviceImpl,
2480 #else
2481  const sdecl::ServiceDecl slideShowDecl(
2482      sdecl::class_<SlideShowImpl>(),
2483 #endif
2484     "com.sun.star.comp.presentation.SlideShow",
2485     "com.sun.star.presentation.SlideShow" );
2486 
2487 // The C shared lib entry points
2488 COMPHELPER_SERVICEDECL_EXPORTS1(slideShowDecl)
2489