Bump version to 6.4-15
[LibreOffice.git] / slideshow / source / engine / eventqueue.cxx
blobe2b909e40185e0f52640d19f09767c85db94a930
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
27 #include <event.hxx>
28 #include <eventqueue.hxx>
29 #include <slideshowexceptions.hxx>
31 #include <limits>
32 #include <memory>
35 using namespace ::com::sun::star;
37 namespace slideshow
39 namespace internal
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 )
51 : maMutex(),
52 maEvents(),
53 maNextEvents(),
54 maNextNextEvents(),
55 mpTimer( 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() )
71 try
73 maEvents.top().pEvent->dispose();
75 catch (const uno::Exception&)
77 TOOLS_WARN_EXCEPTION("slideshow", "");
79 maEvents.pop();
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" );
95 // prepare entry
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
103 // add entry
104 maEvents.push( EventEntry( rEvent, rEvent->getActivationTime(
105 mpTimer->getElapsedTime()) ) );
106 return true;
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()) );
123 return true;
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(
141 EventEntry(
142 rpEvent,
143 rpEvent->getActivationTime(mpTimer->getElapsedTime())));
145 return true;
148 void EventQueue::forceEmpty()
150 ::osl::MutexGuard aGuard( maMutex );
152 process_(true);
155 void EventQueue::process()
157 ::osl::MutexGuard aGuard( maMutex );
159 process_(false);
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()
180 && !bFireAllEvents
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()) );
196 maEvents.pop();
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& )
223 throw;
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
231 // once.
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
245 // once.
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" );
254 else
256 SAL_INFO(
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);
286 return nTimeout;
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: */