1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/diagnose_ex.h>
22 #include <sal/log.hxx>
24 #include <comphelper/anytostring.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
28 #include <eventqueue.hxx>
29 #include <slideshowexceptions.hxx>
35 using namespace ::com::sun::star
;
41 bool EventQueue::EventEntry::operator<( const EventEntry
& rEvent
) const
43 // negate comparison, we want priority queue to be sorted
44 // in increasing order of activation times
45 return nTime
> rEvent
.nTime
;
49 EventQueue::EventQueue(
50 std::shared_ptr
<canvas::tools::ElapsedTime
> const & pPresTimer
)
59 EventQueue::~EventQueue()
61 // add in all that have been added explicitly for this round:
62 for ( const auto& rEvent
: maNextEvents
)
64 maEvents
.push(rEvent
);
66 EventEntryVector().swap( maNextEvents
);
68 // dispose event queue
69 while( !maEvents
.empty() )
73 maEvents
.top().pEvent
->dispose();
75 catch (const uno::Exception
&)
77 TOOLS_WARN_EXCEPTION("slideshow", "");
83 bool EventQueue::addEvent( const EventSharedPtr
& rEvent
)
85 ::osl::MutexGuard
aGuard( maMutex
);
87 SAL_INFO("slideshow.eventqueue", "adding event \"" << rEvent
->GetDescription()
88 << "\" [" << rEvent
.get()
89 << "] at " << mpTimer
->getElapsedTime()
90 << " with delay " << rEvent
->getActivationTime(0.0)
92 ENSURE_OR_RETURN_FALSE( rEvent
,
93 "EventQueue::addEvent: event ptr NULL" );
97 // A seemingly obvious optimization cannot be used here,
98 // because it breaks assumed order of notification: zero
99 // timeout events could be fired() immediately, but that
100 // would not unwind the stack and furthermore changes
101 // order of notification
104 maEvents
.push( EventEntry( rEvent
, rEvent
->getActivationTime(
105 mpTimer
->getElapsedTime()) ) );
109 bool EventQueue::addEventForNextRound( EventSharedPtr
const& rEvent
)
111 ::osl::MutexGuard
aGuard( maMutex
);
113 SAL_INFO("slideshow.eventqueue", "adding event \"" << rEvent
->GetDescription()
114 << "\" [" << rEvent
.get()
115 << "] for the next round at " << mpTimer
->getElapsedTime()
116 << " with delay " << rEvent
->getActivationTime(0.0)
119 ENSURE_OR_RETURN_FALSE( rEvent
.get() != nullptr,
120 "EventQueue::addEvent: event ptr NULL" );
121 maNextEvents
.emplace_back( rEvent
, rEvent
->getActivationTime(
122 mpTimer
->getElapsedTime()) );
126 bool EventQueue::addEventWhenQueueIsEmpty (const EventSharedPtr
& rpEvent
)
128 ::osl::MutexGuard
aGuard( maMutex
);
130 SAL_INFO("slideshow.eventqueue", "adding event \"" << rpEvent
->GetDescription()
131 << "\" [" << rpEvent
.get()
132 << "] for execution when the queue is empty at " << mpTimer
->getElapsedTime()
133 << " with delay " << rpEvent
->getActivationTime(0.0)
136 ENSURE_OR_RETURN_FALSE(
137 rpEvent
.get() != nullptr,
138 "EventQueue::addEvent: event ptr NULL");
140 maNextNextEvents
.push(
143 rpEvent
->getActivationTime(mpTimer
->getElapsedTime())));
148 void EventQueue::forceEmpty()
150 ::osl::MutexGuard
aGuard( maMutex
);
155 void EventQueue::process()
157 ::osl::MutexGuard
aGuard( maMutex
);
162 void EventQueue::process_( bool bFireAllEvents
)
164 SAL_INFO("slideshow.verbose", "EventQueue: heartbeat" );
166 // add in all that have been added explicitly for this round:
167 for ( const auto& rEvent
: maNextEvents
) {
168 maEvents
.push(rEvent
);
170 EventEntryVector().swap( maNextEvents
);
172 // perform topmost, ready-to-execute event
173 // =======================================
175 const double nCurrTime( mpTimer
->getElapsedTime() );
177 // When maEvents does not contain any events that are due now
178 // then process one event from maNextNextEvents.
179 if (!maNextNextEvents
.empty()
181 && (maEvents
.empty() || maEvents
.top().nTime
> nCurrTime
))
183 const EventEntry
aEvent (std::move(maNextNextEvents
.top()));
184 maNextNextEvents
.pop();
185 maEvents
.push(aEvent
);
188 // process ready/elapsed events. Note that the 'perceived'
189 // current time remains constant for this loop, thus we're
190 // processing only those events which where ready when we
191 // entered this method.
192 while( !maEvents
.empty() &&
193 (bFireAllEvents
|| maEvents
.top().nTime
<= nCurrTime
) )
195 EventEntry
event( std::move(maEvents
.top()) );
198 // only process event, if it is still 'charged',
199 // i.e. the fire() call effects something. This is
200 // used when e.g. having events registered at multiple
201 // places, which should fire only once: after the
202 // initial fire() call, those events become inactive
203 // and return false on isCharged. This frees us from
204 // the need to prune queues of those inactive shells.
205 if( event
.pEvent
->isCharged() )
209 SAL_INFO("slideshow.eventqueue", "firing event \""
210 << event
.pEvent
->GetDescription()
211 << "\" [" << event
.pEvent
.get()
212 << "] at " << mpTimer
->getElapsedTime()
213 << " with delay " << event
.pEvent
->getActivationTime(0.0)
215 event
.pEvent
->fire();
216 SAL_INFO("slideshow.eventqueue", "event \""
217 << event
.pEvent
->GetDescription()
218 << "\" [" << event
.pEvent
.get() << "] fired"
221 catch( uno::RuntimeException
& )
225 catch( uno::Exception
& )
227 // catch anything here, we don't want
228 // to leave this scope under _any_
229 // circumstance. Although, do _not_
230 // reinsert an activity that threw
233 // NOTE: we explicitly don't catch(...) here,
234 // since this will also capture segmentation
235 // violations and the like. In such a case, we
236 // still better let our clients now...
237 TOOLS_WARN_EXCEPTION( "slideshow", "" );
239 catch( SlideShowException
& )
241 // catch anything here, we don't want
242 // to leave this scope under _any_
243 // circumstance. Although, do _not_
244 // reinsert an activity that threw
247 // NOTE: we explicitly don't catch(...) here,
248 // since this will also capture segmentation
249 // violations and the like. In such a case, we
250 // still better let our clients now...
251 SAL_WARN("slideshow.eventqueue", "::presentation::internal::EventQueue: Event threw a SlideShowException, action might not have been fully performed" );
257 "slideshow.eventqueue",
258 "Ignoring discharged event: unknown ("
259 << event
.pEvent
.get() << "), timeout was: "
260 << event
.pEvent
->getActivationTime(0.0));
265 bool EventQueue::isEmpty() const
267 ::osl::MutexGuard
aGuard( maMutex
);
269 return maEvents
.empty() && maNextEvents
.empty() && maNextNextEvents
.empty();
272 double EventQueue::nextTimeout() const
274 ::osl::MutexGuard
aGuard( maMutex
);
276 // return time for next entry (if any)
277 double nTimeout (::std::numeric_limits
<double>::max());
278 const double nCurrentTime (mpTimer
->getElapsedTime());
279 if ( ! maEvents
.empty())
280 nTimeout
= maEvents
.top().nTime
- nCurrentTime
;
281 if ( ! maNextEvents
.empty())
282 nTimeout
= ::std::min(nTimeout
, maNextEvents
.front().nTime
- nCurrentTime
);
283 if ( ! maNextNextEvents
.empty())
284 nTimeout
= ::std::min(nTimeout
, maNextNextEvents
.top().nTime
- nCurrentTime
);
289 void EventQueue::clear()
291 ::osl::MutexGuard
aGuard( maMutex
);
293 // TODO(P1): Maybe a plain vector and vector.swap will
294 // be faster here. Profile.
295 maEvents
= ImplQueueType();
297 maNextEvents
.clear();
298 maNextNextEvents
= ImplQueueType();
303 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */