summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slideshow/source/engine/animationnodes/basenode.hxx6
-rw-r--r--slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx6
-rw-r--r--slideshow/source/engine/effectrewinder.cxx404
-rw-r--r--slideshow/source/engine/effectrewinder.hxx183
-rw-r--r--slideshow/source/engine/eventqueue.cxx47
-rw-r--r--slideshow/source/engine/makefile.mk1
-rw-r--r--slideshow/source/engine/screenupdater.cxx83
-rw-r--r--slideshow/source/engine/slideshowimpl.cxx272
-rw-r--r--slideshow/source/engine/usereventqueue.cxx54
-rw-r--r--slideshow/source/inc/eventqueue.hxx8
-rw-r--r--slideshow/source/inc/screenupdater.hxx21
-rw-r--r--slideshow/source/inc/usereventqueue.hxx18
12 files changed, 1029 insertions, 74 deletions
diff --git a/slideshow/source/engine/animationnodes/basenode.hxx b/slideshow/source/engine/animationnodes/basenode.hxx
index a25f6cb92..dbf2f1375 100644
--- a/slideshow/source/engine/animationnodes/basenode.hxx
+++ b/slideshow/source/engine/animationnodes/basenode.hxx
@@ -136,7 +136,9 @@ public:
const AnimationNodeSharedPtr& rNotifee );
// nop:
virtual void notifyDeactivating( const AnimationNodeSharedPtr& rNotifier );
-
+
+ bool isMainSequenceRootNode() const { return mbIsMainSequenceRootNode; }
+
protected:
void scheduleDeactivationEvent( EventSharedPtr const& pEvent =
EventSharedPtr() );
@@ -144,8 +146,6 @@ protected:
SlideShowContext const& getContext() const { return maContext; }
::boost::shared_ptr<BaseNode> const& getSelf() const { return mpSelf; }
- bool isMainSequenceRootNode() const { return mbIsMainSequenceRootNode; }
-
bool checkValidNode() const {
ENSURE_OR_THROW( mpSelf, "no self ptr set!" );
bool const bRet = (meCurrState != INVALID);
diff --git a/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx b/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx
index de6332114..ab0c49237 100644
--- a/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx
+++ b/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx
@@ -88,7 +88,7 @@ void SequentialTimeContainer::skipEffect(
if (isChildNode(pChildNode)) {
// empty all events ignoring timings => until next effect
getContext().mrEventQueue.forceEmpty();
- getContext().mrEventQueue.addEventForNextRound(
+ getContext().mrEventQueue.addEvent(
makeEvent( boost::bind(&AnimationNode::deactivate, pChildNode) ) );
}
else
@@ -125,7 +125,8 @@ bool SequentialTimeContainer::resolveChild(
// deactivate child node when skip event occurs:
getContext().mrUserEventQueue.registerSkipEffectEvent(
- mpCurrentSkipEvent );
+ mpCurrentSkipEvent,
+ mnFinishedChildren+1<maChildren.size());
// rewind to previous child:
getContext().mrUserEventQueue.registerRewindEffectEvent(
mpCurrentRewindEvent );
@@ -136,6 +137,7 @@ bool SequentialTimeContainer::resolveChild(
void SequentialTimeContainer::notifyDeactivating(
AnimationNodeSharedPtr const& rNotifier )
{
+ OSL_TRACE(" SequentialTimeContainer::notifyDeactivating\r");
if (notifyDeactivatedChild( rNotifier ))
return;
diff --git a/slideshow/source/engine/effectrewinder.cxx b/slideshow/source/engine/effectrewinder.cxx
new file mode 100644
index 000000000..aff21d30d
--- /dev/null
+++ b/slideshow/source/engine/effectrewinder.cxx
@@ -0,0 +1,404 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: slideshowimpl.cxx,v $
+ * $Revision: 1.10 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_slideshow.hxx"
+
+#include "EffectRewinder.hxx"
+#include "eventqueue.hxx"
+#include "usereventqueue.hxx"
+#include "mouseeventhandler.hxx"
+#include "animationnodes/basecontainernode.hxx"
+#include "delayevent.hxx"
+
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+using ::com::sun::star::uno::Reference;
+using namespace ::com::sun::star;
+
+namespace slideshow { namespace internal {
+
+
+namespace {
+
+class RewinderEventHandler : public EventHandler
+{
+public:
+ typedef ::boost::function<bool(void)> Action;
+ RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
+ virtual ~RewinderEventHandler (void) {}
+private:
+ const Action maAction;
+ virtual bool handleEvent (void) { return maAction(); }
+};
+
+
+
+class RewinderAnimationEventHandler : public AnimationEventHandler
+{
+public:
+ typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
+ RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
+ virtual ~RewinderAnimationEventHandler (void) {}
+private:
+ const Action maAction;
+ virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode)
+ { return maAction(rpNode); }
+};
+
+
+
+} // end of anonymous namespace
+
+
+//----- EffectRewinder --------------------------------------------------------------
+
+EffectRewinder::EffectRewinder (
+ EventMultiplexer& rEventMultiplexer,
+ EventQueue& rEventQueue,
+ UserEventQueue& rUserEventQueue)
+ : mrEventMultiplexer(rEventMultiplexer),
+ mrEventQueue(rEventQueue),
+ mrUserEventQueue(rUserEventQueue),
+ mpSlideStartHandler(),
+ mpSlideEndHandler(),
+ mpAnimationStartHandler(),
+ mnMainSequenceEffectCount(0),
+ mpAsynchronousRewindEvent(),
+ mxCurrentAnimationRootNode()
+{
+ Initialize();
+}
+
+
+
+
+void EffectRewinder::Initialize (void)
+{
+ // Add some event handlers so that we are informed when
+ // a) an animation is started (we then check whether that belongs to a
+ // main sequence effect and if so, increase the respective counter),
+ // b,c) a slide was started or ended (in which case the effect counter
+ // is reset.
+
+ mpAnimationStartHandler.reset(
+ new RewinderAnimationEventHandler(
+ ::boost::bind(&EffectRewinder::NotifyAnimationStart, this, _1)));
+ mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
+
+ mpSlideStartHandler.reset(
+ new RewinderEventHandler(
+ ::boost::bind(&EffectRewinder::ResetEffectCount, this)));
+ mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
+
+ mpSlideEndHandler.reset(
+ new RewinderEventHandler(
+ ::boost::bind(&EffectRewinder::ResetEffectCount, this)));
+ mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
+}
+
+
+
+
+EffectRewinder::~EffectRewinder (void)
+{
+ Dispose();
+}
+
+
+
+
+void EffectRewinder::Dispose (void)
+{
+ if (mpAsynchronousRewindEvent)
+ {
+ mpAsynchronousRewindEvent->dispose();
+ mpAsynchronousRewindEvent.reset();
+ }
+
+ if (mpAnimationStartHandler)
+ {
+ mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
+ mpAnimationStartHandler.reset();
+ }
+
+ if (mpSlideStartHandler)
+ {
+ mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
+ mpSlideStartHandler.reset();
+ }
+
+ if (mpSlideEndHandler)
+ {
+ mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
+ mpSlideEndHandler.reset();
+ }
+}
+
+
+
+
+void EffectRewinder::SetRootAnimationNode (
+ const uno::Reference<animations::XAnimationNode>& xRootNode)
+{
+ mxCurrentAnimationRootNode = xRootNode;
+}
+
+
+
+
+bool EffectRewinder::Rewind (
+ const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
+ const ::boost::function<void(void)>& rSlideRewindFunctor,
+ const ::boost::function<void(void)>& rPreviousSlideFunctor)
+{
+ mpPaintLock = rpPaintLock;
+
+ // Do not allow nested rewinds.
+ if (mpAsynchronousRewindEvent)
+ {
+ OSL_ASSERT( ! mpAsynchronousRewindEvent);
+ return false;
+ }
+
+ // Abort (and skip over the rest of) any currently active animation.
+ mrUserEventQueue.callSkipEffectEventHandler();
+ mrEventQueue.forceEmpty();
+
+ const int nSkipCount (mnMainSequenceEffectCount - 1);
+ if (nSkipCount < 0)
+ {
+ if ( ! rPreviousSlideFunctor)
+ {
+ OSL_ASSERT(rPreviousSlideFunctor);
+ return false;
+ }
+
+ // No main sequence effects to rewind on the current slide.
+ // Go back to the previous slide.
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::AsynchronousRewindToPreviousSlide,
+ this,
+ rPreviousSlideFunctor));
+ }
+ else
+ {
+ // The actual rewinding is done asynchronously so that we can safely
+ // call other methods.
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::AsynchronousRewind,
+ this,
+ nSkipCount,
+ true,
+ rSlideRewindFunctor));
+ }
+
+ if (mpAsynchronousRewindEvent)
+ mrEventQueue.addEvent(mpAsynchronousRewindEvent);
+
+ return mpAsynchronousRewindEvent.get()!=NULL;
+}
+
+
+
+
+void EffectRewinder::SkipAllMainSequenceEffects (void)
+{
+ // Do not allow nested rewinds.
+ if (mpAsynchronousRewindEvent)
+ {
+ OSL_ASSERT(!mpAsynchronousRewindEvent);
+ return;
+ }
+
+ const int nTotalMainSequenceEffectCount (CountMainSequenceEffects());
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::AsynchronousRewind,
+ this,
+ nTotalMainSequenceEffectCount,
+ false,
+ ::boost::function<void(void)>()));
+ mrEventQueue.addEvent(mpAsynchronousRewindEvent);
+}
+
+
+
+
+sal_Int32 EffectRewinder::CountMainSequenceEffects (void)
+{
+ // Determine the number of main sequence effects.
+ sal_Int32 nMainSequenceNodeCount (0);
+
+ ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
+ aNodeQueue.push(mxCurrentAnimationRootNode);
+ while ( ! aNodeQueue.empty())
+ {
+ const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
+ aNodeQueue.pop();
+
+ // Does the current node belong to the main sequence?
+ if (xNode.is())
+ {
+ animations::Event aEvent;
+ if (xNode->getBegin() >>= aEvent)
+ if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
+ ++nMainSequenceNodeCount;
+ }
+
+ // If the current node is a container then prepare its children for investigation.
+ uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
+ if (xEnumerationAccess.is())
+ {
+ uno::Reference<container::XEnumeration> xEnumeration (
+ xEnumerationAccess->createEnumeration());
+ if (xEnumeration.is())
+ while (xEnumeration->hasMoreElements())
+ {
+ aNodeQueue.push(
+ uno::Reference<animations::XAnimationNode>(
+ xEnumeration->nextElement(), uno::UNO_QUERY));
+ }
+ }
+ }
+
+ return nMainSequenceNodeCount;
+
+ // // Skip all main sequence nodes.
+ // SkipSomeMainSequenceEffects(nMainSequenceNodeCount);
+}
+
+
+
+
+void EffectRewinder::SkipSomeMainSequenceEffects (sal_Int32 nSkipCount)
+{
+ while (--nSkipCount >= 0)
+ SkipSingleMainSequenceEffects();
+}
+
+
+
+
+void EffectRewinder::SkipSingleMainSequenceEffects (void)
+{
+ // This basically just starts the next effect and then skips over its
+ // animation.
+ mrEventMultiplexer.notifyNextEffect();
+ mrEventQueue.forceEmpty();
+ mrUserEventQueue.callSkipEffectEventHandler();
+ mrEventQueue.forceEmpty();
+}
+
+
+
+
+bool EffectRewinder::ResetEffectCount (void)
+{
+ mnMainSequenceEffectCount = 0;
+ return false;
+}
+
+
+
+
+bool EffectRewinder::NotifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
+{
+ // This notification is only relevant for us when the rpNode belongs to
+ // the main sequence.
+ BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode));
+ if (pBaseNode)
+ {
+ BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
+ if (pParent && pParent->isMainSequenceRootNode())
+ {
+ ++mnMainSequenceEffectCount;
+ }
+ }
+ return false;
+}
+
+
+
+
+void EffectRewinder::AsynchronousRewind (
+ sal_Int32 nEffectCount,
+ const bool bRedisplayCurrentSlide,
+ const boost::function<void(void)>& rSlideRewindFunctor)
+{
+ OSL_ASSERT(mpAsynchronousRewindEvent);
+
+ if (bRedisplayCurrentSlide)
+ {
+ mpPaintLock->Activate();
+ // Re-display the current slide.
+ if (rSlideRewindFunctor)
+ rSlideRewindFunctor();
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::AsynchronousRewind,
+ this,
+ nEffectCount,
+ false,
+ rSlideRewindFunctor));
+ mrEventQueue.addEventForNextRound(mpAsynchronousRewindEvent);
+ }
+ else
+ {
+ mrEventQueue.forceEmpty();
+ while (--nEffectCount >= 0)
+ SkipSingleMainSequenceEffects();
+
+ mpAsynchronousRewindEvent.reset();
+ mpPaintLock.reset();
+ }
+}
+
+
+
+
+void EffectRewinder::AsynchronousRewindToPreviousSlide (
+ const ::boost::function<void(void)>& rSlideRewindFunctor)
+{
+ OSL_ASSERT(mpAsynchronousRewindEvent);
+
+ mpAsynchronousRewindEvent.reset();
+ rSlideRewindFunctor();
+}
+
+
+} } // end of namespace ::slideshow::internal
diff --git a/slideshow/source/engine/effectrewinder.hxx b/slideshow/source/engine/effectrewinder.hxx
new file mode 100644
index 000000000..b9ff08a8c
--- /dev/null
+++ b/slideshow/source/engine/effectrewinder.hxx
@@ -0,0 +1,183 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: slideshowimpl.cxx,v $
+ * $Revision: 1.10 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_EFFECT_REWINDER_HXX
+#define INCLUDED_SLIDESHOW_EFFECT_REWINDER_HXX
+
+#include "animationnode.hxx"
+#include "eventhandler.hxx"
+#include "animationeventhandler.hxx"
+#include "event.hxx"
+#include "screenupdater.hxx"
+
+#include <com/sun/star/presentation/XSlideShow.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
+#include <vector>
+
+namespace css = ::com::sun::star;
+
+namespace slideshow { namespace internal {
+
+class EventMultiplexer;
+class EventQueue;
+class UserEventQueue;
+
+/** Rewind single effects of the main effect sequence. A rewind is
+ initiated by calling the Rewind() method. Part of the processing is
+ done asynchronously. Multiple EventQueue::update() calls may be
+ necessary to finish a rewind.
+
+ Remember to call SetRootAnimationNode() when switching to a different
+ slide so that the EffectRewinder can determine the number of main
+ sequence effects.
+*/
+class EffectRewinder
+{
+public:
+ EffectRewinder (
+ EventMultiplexer& rEventMultiplexer,
+ EventQueue& rEventQueue,
+ UserEventQueue& rUserEventQueue);
+ ~EffectRewinder (void);
+
+ /** Call Dispose() before the ownder of an EffectRewinder object dies so
+ that the EffectRewinder can release all references to the owner.
+
+ */
+ void Dispose (void);
+
+ /** Store the root node of the animation tree. It is used in
+ CountMainSequenceEffects() to count the number of main sequence
+ effects (or effect groups.)
+ */
+ void SetRootAnimationNode (
+ const css::uno::Reference<css::animations::XAnimationNode>& xRootNode);
+
+ /** Rewind one effect of the main effect sequence. When the current
+ slide has not effects or no main sequence effect has yet been played
+ then switch to the previous slide and replay all of its main
+ sequence effects.
+ The caller has to pass two functors that redisplay the current slide
+ or switch to the previous slide so that it does not have to expose
+ its internals to us. Only one of the two functors is called.
+ @param rpPaintLock
+ This paint lock is released after the whole asynchronous
+ procoess of rewinding the current effect is completed. It
+ prevents intermediate repaints that would show partial replay
+ of effects.
+ @param rSlideRewindFunctor
+ This functor is called when the current slide is to be
+ redisplayed. When it is called then the other functor is not
+ called.
+ @param rPreviousSlideFunctor
+ This functor is called to switch to the previous slide. When it
+ is called then the other functor is not called.
+ */
+ bool Rewind (
+ const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
+ const ::boost::function<void(void)>& rSlideRewindFunctor,
+ const ::boost::function<void(void)>& rPreviousSlideFunctor);
+
+ /** Call this method after gotoPreviousEffect() triggered a slide change
+ to the previous slide.
+ */
+ void SkipAllMainSequenceEffects (void);
+
+private:
+ EventMultiplexer& mrEventMultiplexer;
+ EventQueue& mrEventQueue;
+ UserEventQueue& mrUserEventQueue;
+
+ EventHandlerSharedPtr mpSlideStartHandler;
+ EventHandlerSharedPtr mpSlideEndHandler;
+ AnimationEventHandlerSharedPtr mpAnimationStartHandler;
+
+ /** The number off main sequence effects so far.
+ */
+ sal_Int32 mnMainSequenceEffectCount;
+
+ /** This is the currently scheduled event that executes the asynchronous
+ part of the effect rewinding. It is also used as flag that prevents
+ nested rewinds.
+ */
+ EventSharedPtr mpAsynchronousRewindEvent;
+
+ css::uno::Reference<css::animations::XAnimationNode> mxCurrentAnimationRootNode;
+ ::boost::shared_ptr<ScreenUpdater::UpdateLock> mpPaintLock;
+
+ void Initialize (void);
+
+ bool ResetEffectCount (void);
+ /** Called by listeners when an animation (not necessarily of a main
+ sequence effect) starts.
+ */
+ bool NotifyAnimationStart (const AnimationNodeSharedPtr& rpNode);
+
+ /** Count the number of effects (or effect groups) in the main effect
+ sequence.
+ */
+ sal_Int32 CountMainSequenceEffects (void);
+
+ /** Skip the next main sequence effect.
+ */
+ void SkipSingleMainSequenceEffects (void);
+
+ /** Skip the specified number of main sequence effects.
+ */
+ void SkipSomeMainSequenceEffects (const sal_Int32 nSkipCount);
+
+ /** Rewind the last effect of the main effect sequence by replaying all
+ previous effects.
+ @param nEffectCount
+ The number of main sequence effects to replay.
+ @param bRedisplayCurrentSlide
+ When <TRUE/> then the current slide is redisplayed before the
+ effects are replayed.
+ @param rSlideRewindFunctor
+ This functor is used to redisplay the current slide.
+ */
+ void AsynchronousRewind (
+ sal_Int32 nEffectCount,
+ const bool bRedisplayCurrentSlide,
+ const boost::function<void(void)>& rSlideRewindFunctor);
+
+ /** Go to the previous slide and replay all of its main sequence effects
+ (or effect groups).
+ @param rPreviousSlideFunctor
+ This functor is used to go to the previous slide.
+ */
+ void AsynchronousRewindToPreviousSlide (
+ const ::boost::function<void(void)>& rPreviousSlideFunctor);
+};
+
+} } // end of namespace ::slideshow::internal
+
+#endif
diff --git a/slideshow/source/engine/eventqueue.cxx b/slideshow/source/engine/eventqueue.cxx
index cd1eb3789..087d4d5d7 100644
--- a/slideshow/source/engine/eventqueue.cxx
+++ b/slideshow/source/engine/eventqueue.cxx
@@ -66,6 +66,7 @@ namespace slideshow
: maMutex(),
maEvents(),
maNextEvents(),
+ maNextNextEvents(),
mpTimer( pPresTimer )
{
}
@@ -131,6 +132,22 @@ namespace slideshow
mpTimer->getElapsedTime()) ) );
return true;
}
+
+ bool EventQueue::addEventWhenQueueIsEmpty (const EventSharedPtr& rpEvent)
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ ENSURE_OR_RETURN(
+ rpEvent.get() != NULL,
+ "EventQueue::addEvent: event ptr NULL");
+
+ maNextNextEvents.push(
+ EventEntry(
+ rpEvent,
+ rpEvent->getActivationTime(mpTimer->getElapsedTime())));
+
+ return true;
+ }
void EventQueue::forceEmpty()
{
@@ -157,12 +174,23 @@ namespace slideshow
maEvents.push(*iPos);
}
EventEntryVector().swap( maNextEvents );
-
+
// perform topmost, ready-to-execute event
// =======================================
const double nCurrTime( mpTimer->getElapsedTime() );
-
+
+ // When maEvents does not contain any events that are due now
+ // then process one event from maNextNextEvents.
+ if (!maNextNextEvents.empty()
+ && !bFireAllEvents
+ && (maEvents.empty() || maEvents.top().nTime > nCurrTime))
+ {
+ const EventEntry aEvent (maNextNextEvents.top());
+ maNextNextEvents.pop();
+ maEvents.push(aEvent);
+ }
+
// process ready/elapsed events. Note that the 'perceived'
// current time remains constant for this loop, thus we're
// processing only those events which where ready when we
@@ -243,7 +271,7 @@ namespace slideshow
{
::osl::MutexGuard aGuard( maMutex );
- return maEvents.empty();
+ return maEvents.empty() && maNextEvents.empty() && maNextNextEvents.empty();
}
double EventQueue::nextTimeout() const
@@ -251,9 +279,16 @@ namespace slideshow
::osl::MutexGuard aGuard( maMutex );
// return time for next entry (if any)
- return isEmpty() ?
- ::std::numeric_limits<double>::max() :
- maEvents.top().nTime - mpTimer->getElapsedTime();
+ double nTimeout (::std::numeric_limits<double>::max());
+ const double nCurrentTime (mpTimer->getElapsedTime());
+ if ( ! maEvents.empty())
+ nTimeout = maEvents.top().nTime - nCurrentTime;
+ if ( ! maNextEvents.empty())
+ nTimeout = ::std::min(nTimeout, maNextEvents.front().nTime - nCurrentTime);
+ if ( ! maNextNextEvents.empty())
+ nTimeout = ::std::min(nTimeout, maNextNextEvents.top().nTime - nCurrentTime);
+
+ return nTimeout;
}
void EventQueue::clear()
diff --git a/slideshow/source/engine/makefile.mk b/slideshow/source/engine/makefile.mk
index ba00e028b..8316355c6 100644
--- a/slideshow/source/engine/makefile.mk
+++ b/slideshow/source/engine/makefile.mk
@@ -70,6 +70,7 @@ SLOFILES = $(SLO)$/activitiesqueue.obj \
$(SLO)$/attributemap.obj \
$(SLO)$/color.obj \
$(SLO)$/delayevent.obj \
+ $(SLO)$/effectrewinder.obj \
$(SLO)$/eventmultiplexer.obj \
$(SLO)$/eventqueue.obj \
$(SLO)$/expressionnodefactory.obj \
diff --git a/slideshow/source/engine/screenupdater.cxx b/slideshow/source/engine/screenupdater.cxx
index bf3ca0c5b..8cfaaddf2 100644
--- a/slideshow/source/engine/screenupdater.cxx
+++ b/slideshow/source/engine/screenupdater.cxx
@@ -36,6 +36,19 @@
#include <vector>
#include <algorithm>
+namespace {
+ class UpdateLock : public ::slideshow::internal::ScreenUpdater::UpdateLock
+ {
+ public:
+ UpdateLock (::slideshow::internal::ScreenUpdater& rUpdater, const bool bStartLocked);
+ virtual ~UpdateLock (void);
+ virtual void Activate (void);
+ private:
+ ::slideshow::internal::ScreenUpdater& mrUpdater;
+ bool mbIsActivated;
+ };
+}
+
namespace slideshow
{
namespace internal
@@ -64,12 +77,16 @@ namespace internal
/// True, if at least one notifyUpdate() call had bViewClobbered set
bool mbViewClobbered;
+ /// The screen is updated only when mnLockCount==0
+ sal_Int32 mnLockCount;
+
explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) :
maUpdaters(),
maViewUpdateRequests(),
mrViewContainer(rViewContainer),
mbUpdateAllRequest(false),
- mbViewClobbered(false)
+ mbViewClobbered(false),
+ mnLockCount(0)
{}
};
@@ -100,6 +117,9 @@ namespace internal
void ScreenUpdater::commitUpdates()
{
+ if (mpImpl->mnLockCount > 0)
+ return;
+
// cases:
//
// (a) no update necessary at all
@@ -178,6 +198,9 @@ namespace internal
void ScreenUpdater::requestImmediateUpdate()
{
+ if (mpImpl->mnLockCount > 0)
+ return;
+
// TODO(F2): This will interfere with other updates, since it
// happens out-of-sync with main animation loop. Might cause
// artifacts.
@@ -186,5 +209,63 @@ namespace internal
boost::mem_fn(&View::updateScreen) );
}
+ void ScreenUpdater::lockUpdates (void)
+ {
+ ++mpImpl->mnLockCount;
+ OSL_ASSERT(mpImpl->mnLockCount>0);
+ }
+
+ void ScreenUpdater::unlockUpdates (void)
+ {
+ OSL_ASSERT(mpImpl->mnLockCount>0);
+ if (mpImpl->mnLockCount > 0)
+ {
+ --mpImpl->mnLockCount;
+ if (mpImpl->mnLockCount)
+ commitUpdates();
+ }
+ }
+
+ ::boost::shared_ptr<ScreenUpdater::UpdateLock> ScreenUpdater::createLock (const bool bStartLocked)
+ {
+ return ::boost::shared_ptr<ScreenUpdater::UpdateLock>(new ::UpdateLock(*this, bStartLocked));
+ }
+
+
} // namespace internal
} // namespace slideshow
+
+namespace {
+
+UpdateLock::UpdateLock (
+ ::slideshow::internal::ScreenUpdater& rUpdater,
+ const bool bStartLocked)
+ : mrUpdater(rUpdater),
+ mbIsActivated(false)
+{
+ if (bStartLocked)
+ Activate();
+}
+
+
+
+
+UpdateLock::~UpdateLock (void)
+{
+ if (mbIsActivated)
+ mrUpdater.unlockUpdates();
+}
+
+
+
+
+void UpdateLock::Activate (void)
+{
+ if ( ! mbIsActivated)
+ {
+ mbIsActivated = true;
+ mrUpdater.lockUpdates();
+ }
+}
+
+}
diff --git a/slideshow/source/engine/slideshowimpl.cxx b/slideshow/source/engine/slideshowimpl.cxx
index 94f89a3f5..b608acf4e 100644
--- a/slideshow/source/engine/slideshowimpl.cxx
+++ b/slideshow/source/engine/slideshowimpl.cxx
@@ -92,6 +92,7 @@
#include "slidebitmap.hxx"
#include "rehearsetimingsactivity.hxx"
#include "waitsymbol.hxx"
+#include "effectrewinder.hxx"
#include <boost/noncopyable.hpp>
#include <boost/bind.hpp>
@@ -193,7 +194,7 @@ public:
This method notifies the end of the third phase.
*/
- void notifySlideEnded();
+ void notifySlideEnded (const bool bReverse);
/** Notification from eventmultiplexer that a hyperlink
has been clicked.
@@ -208,6 +209,7 @@ public:
private:
// XSlideShow:
virtual sal_Bool SAL_CALL nextEffect() throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL previousEffect() throw (uno::RuntimeException);
virtual sal_Bool SAL_CALL startShapeActivity(
uno::Reference<drawing::XShape> const& xShape )
throw (uno::RuntimeException);
@@ -258,6 +260,12 @@ private:
virtual bool requestCursor( sal_Int16 nCursorShape );
virtual void resetCursor();
+ /** This is somewhat similar to displaySlide when called for the current
+ slide. It has been simplified to take advantage of that no slide
+ change takes place. Furthermore it does not show the slide
+ transition.
+ */
+ void redisplayCurrentSlide (void);
protected:
// WeakComponentImplHelperBase
@@ -313,12 +321,32 @@ private:
const SlideSharedPtr& rEnteringSlide,
const EventSharedPtr& rTransitionEndEvent );
- /// Display/hide wait symbol on all views
- void setWaitState( bool bOn );
+ /** Request/release the wait symbol. The wait symbol is displayed when
+ there are more requests then releases. Locking the wait symbol
+ helps to avoid intermediate repaints.
+
+ Do not call this method directly. Use WaitSymbolLock instead.
+ */
+ void requestWaitSymbol (void);
+ void releaseWaitSymbol (void);
+
+ class WaitSymbolLock {public:
+ WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
+ { mrSlideShowImpl.requestWaitSymbol(); }
+ ~WaitSymbolLock(void)
+ { mrSlideShowImpl.releaseWaitSymbol(); }
+ private: SlideShowImpl& mrSlideShowImpl;
+ };
+
/// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
+ /** This method is called asynchronously to finish the rewinding of an
+ effect to the previous slide that was initiated earlier.
+ */
+ void rewindEffectToPreviousSlide (void);
+
/// all registered views
UnoViewContainer maViewContainer;
@@ -365,7 +393,7 @@ private:
sal_Int16 mnCurrentCursor;
- bool mbWaitState;
+ sal_Int32 mnWaitSymbolRequestCount;
bool mbAutomaticAdvancementMode;
bool mbImageAnimationsAllowed;
bool mbNoSlideTransitions;
@@ -374,6 +402,8 @@ private:
bool mbShowPaused;
bool mbSlideShowIdle;
bool mbDisableAnimationZOrder;
+
+ EffectRewinder maEffectRewinder;
};
@@ -465,7 +495,7 @@ SlideShowImpl::SlideShowImpl(
mxPrefetchSlide(),
mxPrefetchAnimationNode(),
mnCurrentCursor(awt::SystemPointer::ARROW),
- mbWaitState(false),
+ mnWaitSymbolRequestCount(0),
mbAutomaticAdvancementMode(false),
mbImageAnimationsAllowed( true ),
mbNoSlideTransitions( false ),
@@ -473,7 +503,8 @@ SlideShowImpl::SlideShowImpl(
mbForceManualAdvance( false ),
mbShowPaused( false ),
mbSlideShowIdle( true ),
- mbDisableAnimationZOrder( false )
+ mbDisableAnimationZOrder( false ),
+ maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue)
{
// keep care not constructing any UNO references to this inside ctor,
// shift that code to create()!
@@ -507,6 +538,8 @@ void SlideShowImpl::disposing()
{
osl::MutexGuard const guard( m_aMutex );
+ maEffectRewinder.Dispose();
+
// stop slide transition sound, if any:
stopSlideTransitionSound();
@@ -607,7 +640,7 @@ ActivitySharedPtr SlideShowImpl::createSlideTransition(
const uno::Reference< drawing::XDrawPage >& xDrawPage,
const SlideSharedPtr& rLeavingSlide,
const SlideSharedPtr& rEnteringSlide,
- const EventSharedPtr& rTransitionEndEvent )
+ const EventSharedPtr& rTransitionEndEvent)
{
ENSURE_OR_THROW( !maViewContainer.empty(),
"createSlideTransition(): No views" );
@@ -692,7 +725,7 @@ ActivitySharedPtr SlideShowImpl::createSlideTransition(
bTransitionDirection,
aTransitionFadeColor,
resetSlideTransitionSound( aSound, bLoopSound ) ));
-
+
if( !pTransition )
return ActivitySharedPtr(); // no transition effect has been
// generated. Normally, that means
@@ -778,20 +811,43 @@ SlideSharedPtr SlideShowImpl::makeSlide(
return pSlide;
}
-void SlideShowImpl::setWaitState( bool bOn )
+void SlideShowImpl::requestWaitSymbol (void)
{
- mbWaitState = bOn;
- if( !mpWaitSymbol ) // fallback to cursor
- requestCursor(awt::SystemPointer::WAIT);
- else if( mbWaitState )
- mpWaitSymbol->show();
- else
- mpWaitSymbol->hide();
+ ++mnWaitSymbolRequestCount;
+ OSL_ASSERT(mnWaitSymbolRequestCount>0);
+
+ if (mnWaitSymbolRequestCount == 1)
+ {
+ if( !mpWaitSymbol )
+ {
+ // fall back to cursor
+ requestCursor(calcActiveCursor(mnCurrentCursor));
+ }
+ else
+ mpWaitSymbol->show();
+ }
+}
+
+void SlideShowImpl::releaseWaitSymbol (void)
+{
+ --mnWaitSymbolRequestCount;
+ OSL_ASSERT(mnWaitSymbolRequestCount>=0);
+
+ if (mnWaitSymbolRequestCount == 0)
+ {
+ if( !mpWaitSymbol )
+ {
+ // fall back to cursor
+ requestCursor(calcActiveCursor(mnCurrentCursor));
+ }
+ else
+ mpWaitSymbol->hide();
+ }
}
sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
{
- if( mbWaitState && !mpWaitSymbol ) // enforce wait cursor
+ if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
nCursorShape = awt::SystemPointer::WAIT;
else if( !mbMouseVisible ) // enforce INVISIBLE
nCursorShape = awt::SystemPointer::INVISIBLE;
@@ -835,10 +891,19 @@ void SlideShowImpl::stopShow()
}
}
-struct SlideShowImpl::PrefetchPropertiesFunc
+
+
+class SlideShowImpl::PrefetchPropertiesFunc
{
- SlideShowImpl *const that;
- PrefetchPropertiesFunc( SlideShowImpl * that_ ) : that(that_) {}
+public:
+ PrefetchPropertiesFunc( SlideShowImpl * that_,
+ bool& rbSkipAllMainSequenceEffects,
+ bool& rbSkipSlideTransition)
+ : mpSlideShowImpl(that_),
+ mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
+ mrbSkipSlideTransition(rbSkipSlideTransition)
+ {}
+
void operator()( beans::PropertyValue const& rProperty ) const {
if (rProperty.Name.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("Prefetch") ))
@@ -846,16 +911,30 @@ struct SlideShowImpl::PrefetchPropertiesFunc
uno::Sequence<uno::Any> seq;
if ((rProperty.Value >>= seq) && seq.getLength() == 2)
{
- seq[0] >>= that->mxPrefetchSlide;
- seq[1] >>= that->mxPrefetchAnimationNode;
+ seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
+ seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
}
}
+ else if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SkipAllMainSequenceEffects") ))
+ {
+ rProperty.Value >>= mrbSkipAllMainSequenceEffects;
+ }
+ else if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SkipSlideTransition") ))
+ {
+ rProperty.Value >>= mrbSkipSlideTransition;
+ }
else
{
OSL_ENSURE( false, rtl::OUStringToOString(
rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
}
}
+private:
+ SlideShowImpl *const mpSlideShowImpl;
+ bool& mrbSkipAllMainSequenceEffects;
+ bool& mrbSkipSlideTransition;
};
void SlideShowImpl::displaySlide(
@@ -868,7 +947,9 @@ void SlideShowImpl::displaySlide(
if (isDisposed())
return;
-
+
+ maEffectRewinder.SetRootAnimationNode(xRootNode);
+
// precondition: must only be called from the main thread!
DBG_TESTSOLARMUTEX();
@@ -880,20 +961,20 @@ void SlideShowImpl::displaySlide(
// unconditionally. Otherwise, genuine
// shape animations (drawing layer and
// GIF) will not be stopped.
-
+
+ bool bSkipAllMainSequenceEffects (false);
+ bool bSkipSlideTransition (false);
std::for_each( rProperties.getConstArray(),
rProperties.getConstArray() + rProperties.getLength(),
- PrefetchPropertiesFunc(this) );
+ PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
if (maViewContainer.empty())
return;
-
+
// this here might take some time
{
- comphelper::ScopeGuard const scopeGuard(
- boost::bind( &SlideShowImpl::setWaitState, this, false ) );
- setWaitState(true);
+ WaitSymbolLock aLock (*this);
mpPreviousSlide = mpCurrentSlide;
mpCurrentSlide.reset();
@@ -935,15 +1016,25 @@ void SlideShowImpl::displaySlide(
// create slide transition, and add proper end event
// (which then starts the slide effects
// via CURRENT_SLIDE.show())
- ActivitySharedPtr const pSlideChangeActivity(
- createSlideTransition( mpCurrentSlide->getXDrawPage(),
- mpPreviousSlide,
- mpCurrentSlide,
- makeEvent(
- boost::bind(
- &SlideShowImpl::notifySlideTransitionEnded,
- this,
- false ))));
+ ActivitySharedPtr pSlideChangeActivity (
+ createSlideTransition(
+ mpCurrentSlide->getXDrawPage(),
+ mpPreviousSlide,
+ mpCurrentSlide,
+ makeEvent(
+ boost::bind(
+ &SlideShowImpl::notifySlideTransitionEnded,
+ this,
+ false ))));
+
+ if (bSkipSlideTransition)
+ {
+ // The transition activity was created for the side effects
+ // (like sound transitions). Because we want to skip the
+ // acutual transition animation we do not need the activity
+ // anymore.
+ pSlideChangeActivity.reset();
+ }
if (pSlideChangeActivity)
{
@@ -967,6 +1058,43 @@ void SlideShowImpl::displaySlide(
maEventMultiplexer.notifySlideTransitionStarted();
maListenerContainer.forEach<presentation::XSlideShowListener>(
boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
+
+ // We are currently rewinding an effect. This lead us from the next
+ // slide to this one. To complete this we have to play back all main
+ // sequence effects on this slide.
+ if (bSkipAllMainSequenceEffects)
+ maEffectRewinder.SkipAllMainSequenceEffects();
+}
+
+void SlideShowImpl::redisplayCurrentSlide (void)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+ stopShow();
+ bool bSkipAllMainSequenceEffects (false);
+ bool bSkipSlideTransition (true);
+
+ OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
+ if (maViewContainer.empty())
+ return;
+
+ // No transition effect on this slide - schedule slide
+ // effect start event right away.
+ maEventQueue.addEvent(
+ makeEvent(
+ boost::bind(
+ &SlideShowImpl::notifySlideTransitionEnded,
+ this,
+ true )));
+
+ maEventMultiplexer.notifySlideTransitionStarted();
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
}
sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException)
@@ -985,6 +1113,50 @@ sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException)
return maEventMultiplexer.notifyNextEffect();
}
+
+sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (mbShowPaused)
+ return true;
+ else
+ {
+ return maEffectRewinder.Rewind(
+ maScreenUpdater.createLock(false),
+ ::boost::bind(&SlideShowImpl::redisplayCurrentSlide, this),
+ ::boost::bind(&SlideShowImpl::rewindEffectToPreviousSlide, this));
+ }
+}
+
+void SlideShowImpl::rewindEffectToPreviousSlide (void)
+{
+ // Show the wait symbol now and prevent it from showing temporary slide
+ // content while effects are played back.
+ WaitSymbolLock aLock (*this);
+
+ // A previous call to EffectRewinder::Rewind could not rewind the current
+ // effect because there are no effects on the current slide or none has
+ // yet been displayed. Go to the previous slide.
+ notifySlideEnded(true);
+
+ // Process pending events once more in order to have the following
+ // screen update show the last effect. Not sure whether this should be
+ // necessary.
+ maEventQueue.forceEmpty();
+
+ // We have to call the screen updater before the wait symbol is turned
+ // off. Otherwise the wait symbol would force the display of an
+ // intermediate state of the slide (before the effects are replayed.)
+ maScreenUpdater.commitUpdates();
+}
+
sal_Bool SlideShowImpl::startShapeActivity(
uno::Reference<drawing::XShape> const& /*xShape*/ )
throw (uno::RuntimeException)
@@ -1658,7 +1830,7 @@ void SlideShowImpl::notifySlideAnimationsEnded()
// schedule a slide end event, with automatic mode's
// delay
aNotificationEvents = makeInterruptableDelay(
- boost::bind( &SlideShowImpl::notifySlideEnded, this ),
+ boost::bind( &SlideShowImpl::notifySlideEnded, this, false ),
maEventMultiplexer.getAutomaticTimeout() );
}
else
@@ -1683,7 +1855,7 @@ void SlideShowImpl::notifySlideAnimationsEnded()
bHasAutomaticNextSlide )
{
aNotificationEvents = makeInterruptableDelay(
- boost::bind( &SlideShowImpl::notifySlideEnded, this ),
+ boost::bind( &SlideShowImpl::notifySlideEnded, this, false ),
nAutomaticNextSlideTimeout);
// TODO(F2): Provide a mechanism to let the user override
@@ -1700,7 +1872,7 @@ void SlideShowImpl::notifySlideAnimationsEnded()
// timeout involved.
aNotificationEvents.mpImmediateEvent =
makeEvent( boost::bind(
- &SlideShowImpl::notifySlideEnded, this ) );
+ &SlideShowImpl::notifySlideEnded, this, false ) );
}
}
@@ -1721,9 +1893,7 @@ void SlideShowImpl::notifySlideAnimationsEnded()
// change setup time a lot). Show the wait cursor, this
// indeed might take some seconds.
{
- comphelper::ScopeGuard const scopeGuard(
- boost::bind( &SlideShowImpl::setWaitState, this, false ) );
- setWaitState(true);
+ WaitSymbolLock aLock (*this);
if (! matches( mpPrefetchSlide,
mxPrefetchSlide, mxPrefetchAnimationNode ))
@@ -1745,13 +1915,13 @@ void SlideShowImpl::notifySlideAnimationsEnded()
boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
}
-void SlideShowImpl::notifySlideEnded()
+void SlideShowImpl::notifySlideEnded (const bool bReverse)
{
osl::MutexGuard const guard( m_aMutex );
OSL_ENSURE( !isDisposed(), "### already disposed!" );
- if (mpRehearseTimingsActivity)
+ if (mpRehearseTimingsActivity && !bReverse)
{
const double time = mpRehearseTimingsActivity->stop();
if (mpRehearseTimingsActivity->hasBeenClicked())
@@ -1771,8 +1941,9 @@ void SlideShowImpl::notifySlideEnded()
}
}
}
-
- maEventMultiplexer.notifySlideEndEvent();
+
+ if (bReverse)
+ maEventMultiplexer.notifySlideEndEvent();
stopShow(); // MUST call that: results in
// maUserEventQueue.clear(). What's more,
@@ -1784,7 +1955,10 @@ void SlideShowImpl::notifySlideEnded()
// GIF) will not be stopped.
maListenerContainer.forEach<presentation::XSlideShowListener>(
- boost::mem_fn( &presentation::XSlideShowListener::slideEnded ) );
+ boost::bind(
+ &presentation::XSlideShowListener::slideEnded,
+ _1,
+ bReverse) );
}
bool SlideShowImpl::notifyHyperLinkClicked( rtl::OUString const& hyperLink )
diff --git a/slideshow/source/engine/usereventqueue.cxx b/slideshow/source/engine/usereventqueue.cxx
index 1ead45a9d..774fd0acb 100644
--- a/slideshow/source/engine/usereventqueue.cxx
+++ b/slideshow/source/engine/usereventqueue.cxx
@@ -306,26 +306,46 @@ public:
EventMultiplexer & rEventMultiplexer )
: ClickEventHandler(rEventQueue),
mrEventQueue(rEventQueue),
- mrEventMultiplexer(rEventMultiplexer) {}
+ mrEventMultiplexer(rEventMultiplexer),
+ mbSkipTriggersNextEffect(true) {}
+
+ /** Remember to trigger (or not to trigger) the next effect after the
+ current effect is skiped.
+ */
+ void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
+ { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
+
+ /// Skip the current effect but do not triggere the next effect.
+ void skipEffect (void) { handleEvent_impl(false); }
private:
virtual bool handleEvent_impl()
{
+ return handleEvent_impl(true);
+ }
+
+ bool handleEvent_impl (bool bNotifyNextEffect)
+ {
// fire all events, so animation nodes can register their
// next effect listeners:
if(fireAllEvents( maEvents, mrEventQueue ))
{
- // then simulate a next effect event:
- // this skip effect handler is triggered upon next effect
- // events (multiplexer prio=-1)!
- // Posting a notifyNextEffect() here is only safe
- // (we don't run into busy loop), because we assume that
- // someone has registerered above for next effects
- // (multiplexer prio=0) at the user event queue.
- return mrEventQueue.addEventForNextRound(
- makeEvent( boost::bind(
+ makeEvent(::boost::bind(&EventQueue::forceEmpty, ::boost::ref(mrEventQueue)));
+ if (mbSkipTriggersNextEffect && bNotifyNextEffect)
+ {
+ // then simulate a next effect event: this skip effect
+ // handler is triggered upon next effect events (multiplexer
+ // prio=-1)! Posting a notifyNextEffect() here is only safe
+ // (we don't run into busy loop), because we assume that
+ // someone has registerered above for next effects
+ // (multiplexer prio=0) at the user event queue.
+ return mrEventQueue.addEventWhenQueueIsEmpty(
+ makeEvent( boost::bind(
&EventMultiplexer::notifyNextEffect,
boost::ref(mrEventMultiplexer) ) ) );
+ }
+ else
+ return true;
}
return false;
}
@@ -333,6 +353,7 @@ private:
private:
EventQueue & mrEventQueue;
EventMultiplexer & mrEventMultiplexer;
+ bool mbSkipTriggersNextEffect;
};
class RewindEffectEventHandler : public MouseEventHandler_,
@@ -888,7 +909,9 @@ void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
mbAdvanceOnClick ) );
}
-void UserEventQueue::registerSkipEffectEvent( EventSharedPtr const & pEvent )
+void UserEventQueue::registerSkipEffectEvent(
+ EventSharedPtr const & pEvent,
+ const bool bSkipTriggersNextEffect)
{
if(!mpSkipEffectEventHandler)
{
@@ -905,6 +928,7 @@ void UserEventQueue::registerSkipEffectEvent( EventSharedPtr const & pEvent )
// we're called here)
mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
}
+ mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
mpSkipEffectEventHandler->addEvent( pEvent );
}
@@ -973,6 +997,14 @@ void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
0.0 /* default prio */ ) );
}
+void UserEventQueue::callSkipEffectEventHandler (void)
+{
+ ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
+ ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
+ if (pHandler)
+ pHandler->skipEffect();
+}
+
} // namespace internal
} // namespace presentation
diff --git a/slideshow/source/inc/eventqueue.hxx b/slideshow/source/inc/eventqueue.hxx
index 3d71887e8..9390ce0a2 100644
--- a/slideshow/source/inc/eventqueue.hxx
+++ b/slideshow/source/inc/eventqueue.hxx
@@ -71,6 +71,13 @@ namespace slideshow
process() are postponed to next process().
*/
bool addEventForNextRound( const EventSharedPtr& event );
+
+ /** Another way to control the order of asynchronous event
+ exeqution. Use this method to schedule events that are to
+ be executed after all regular events that have no delay,
+ even when they schedule new regular events without delay.
+ */
+ bool addEventWhenQueueIsEmpty (const EventSharedPtr& rpEvent);
/** Process the event queue.
@@ -138,6 +145,7 @@ namespace slideshow
ImplQueueType maEvents;
typedef ::std::vector<EventEntry> EventEntryVector;
EventEntryVector maNextEvents;
+ ImplQueueType maNextNextEvents;
void process_( bool bFireAllEvents );
// perform timing of events via relative time
diff --git a/slideshow/source/inc/screenupdater.hxx b/slideshow/source/inc/screenupdater.hxx
index 26c40a8ef..10d500b88 100644
--- a/slideshow/source/inc/screenupdater.hxx
+++ b/slideshow/source/inc/screenupdater.hxx
@@ -111,9 +111,30 @@ namespace slideshow
*/
void requestImmediateUpdate();
+ class UpdateLock {public: virtual void Activate (void) = 0; };
+
+ /** Call this method to create a lock instead of calling
+ lockUpdates() and unlockUpdates() directly.
+ @param bStartLocked
+ When <TRUE/> then the UpdateLock is created already
+ locked. When <FALSE/> then Activate() has to be called in order
+ to lock the lock.
+ */
+ ::boost::shared_ptr<UpdateLock> createLock (const bool bStartLocked);
+
+ /** Lock updates to prevent intermediate repaints.
+ */
+ void lockUpdates (void);
+
+ /** When called as often as lockUpdates() then commitUpdates()
+ is called.
+ */
+ void unlockUpdates (void);
+
private:
struct ImplScreenUpdater;
boost::scoped_ptr<ImplScreenUpdater> mpImpl;
+
};
}
}
diff --git a/slideshow/source/inc/usereventqueue.hxx b/slideshow/source/inc/usereventqueue.hxx
index fb8026d67..c9613faa9 100644
--- a/slideshow/source/inc/usereventqueue.hxx
+++ b/slideshow/source/inc/usereventqueue.hxx
@@ -188,8 +188,16 @@ public:
Then, all registered events are fired and removed from this
queue. After firing, a next effect event is issued to this
queue to start the next effect.
+ @param pEvent
+ The event to execute when skipping the current effect.
+ @param bSkipTriggersNextEffect
+ When <TRUE/> then after skipping the current effect the next
+ effect is triggered. When <FALSE/> then the next effect is not
+ triggered.
*/
- void registerSkipEffectEvent( EventSharedPtr const& pEvent );
+ void registerSkipEffectEvent(
+ EventSharedPtr const& pEvent,
+ const bool bSkipTriggersNextEffect);
/** Registes an event that is fired when the current effects(s)
are rewound, .e.g. when the right mouse button is pressed.
@@ -262,7 +270,13 @@ public:
*/
void registerMouseLeaveEvent( const EventSharedPtr& rEvent,
const ShapeSharedPtr& rShape );
-
+
+ /** Typically skipping the current effect is triggered by mouse clicks
+ or key presses that trigger the next effect. This method allows the
+ skipping of effects to be triggered programatically.
+ */
+ void callSkipEffectEventHandler (void);
+
private:
/** Generically register an event on one of the handlers.