1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir // must be first 32*cdf0e10cSrcweir #include <canvas/debug.hxx> 33*cdf0e10cSrcweir #include <tools/diagnose_ex.h> 34*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 35*cdf0e10cSrcweir #include "debug.hxx" 36*cdf0e10cSrcweir 37*cdf0e10cSrcweir #include <comphelper/anytostring.hxx> 38*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include <event.hxx> 41*cdf0e10cSrcweir #include <eventqueue.hxx> 42*cdf0e10cSrcweir #include <slideshowexceptions.hxx> 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir #include <boost/shared_ptr.hpp> 45*cdf0e10cSrcweir #include <limits> 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir using namespace ::com::sun::star; 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir namespace slideshow 51*cdf0e10cSrcweir { 52*cdf0e10cSrcweir namespace internal 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir bool EventQueue::EventEntry::operator<( const EventEntry& rEvent ) const 55*cdf0e10cSrcweir { 56*cdf0e10cSrcweir // negate comparison, we want priority queue to be sorted 57*cdf0e10cSrcweir // in increasing order of activation times 58*cdf0e10cSrcweir return this->nTime > rEvent.nTime; 59*cdf0e10cSrcweir } 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir EventQueue::EventQueue( 63*cdf0e10cSrcweir boost::shared_ptr<canvas::tools::ElapsedTime> const & pPresTimer ) 64*cdf0e10cSrcweir : maMutex(), 65*cdf0e10cSrcweir maEvents(), 66*cdf0e10cSrcweir maNextEvents(), 67*cdf0e10cSrcweir maNextNextEvents(), 68*cdf0e10cSrcweir mpTimer( pPresTimer ) 69*cdf0e10cSrcweir { 70*cdf0e10cSrcweir } 71*cdf0e10cSrcweir 72*cdf0e10cSrcweir EventQueue::~EventQueue() 73*cdf0e10cSrcweir { 74*cdf0e10cSrcweir // add in all that have been added explicitly for this round: 75*cdf0e10cSrcweir EventEntryVector::const_iterator const iEnd( maNextEvents.end() ); 76*cdf0e10cSrcweir for ( EventEntryVector::const_iterator iPos( maNextEvents.begin() ); 77*cdf0e10cSrcweir iPos != iEnd; ++iPos ) 78*cdf0e10cSrcweir { 79*cdf0e10cSrcweir maEvents.push(*iPos); 80*cdf0e10cSrcweir } 81*cdf0e10cSrcweir EventEntryVector().swap( maNextEvents ); 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir // dispose event queue 84*cdf0e10cSrcweir while( !maEvents.empty() ) 85*cdf0e10cSrcweir { 86*cdf0e10cSrcweir try 87*cdf0e10cSrcweir { 88*cdf0e10cSrcweir maEvents.top().pEvent->dispose(); 89*cdf0e10cSrcweir } 90*cdf0e10cSrcweir catch (uno::Exception &) 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir OSL_ENSURE( false, rtl::OUStringToOString( 93*cdf0e10cSrcweir comphelper::anyToString( 94*cdf0e10cSrcweir cppu::getCaughtException() ), 95*cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 96*cdf0e10cSrcweir } 97*cdf0e10cSrcweir maEvents.pop(); 98*cdf0e10cSrcweir } 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir bool EventQueue::addEvent( const EventSharedPtr& rEvent ) 102*cdf0e10cSrcweir { 103*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS) 106*cdf0e10cSrcweir OSL_TRACE("adding at %f event [%s] at %x with delay %f\r", 107*cdf0e10cSrcweir mpTimer->getElapsedTime(), 108*cdf0e10cSrcweir OUStringToOString(rEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(), 109*cdf0e10cSrcweir rEvent.get(), 110*cdf0e10cSrcweir rEvent->getActivationTime(0.0)); 111*cdf0e10cSrcweir #endif 112*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( rEvent, 113*cdf0e10cSrcweir "EventQueue::addEvent: event ptr NULL" ); 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir // prepare entry 116*cdf0e10cSrcweir 117*cdf0e10cSrcweir // A seemingly obvious optimization cannot be used here, 118*cdf0e10cSrcweir // because it breaks assumed order of notification: zero 119*cdf0e10cSrcweir // timeout events could be fired() immediately, but that 120*cdf0e10cSrcweir // would not unwind the stack and furthermore changes 121*cdf0e10cSrcweir // order of notification 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir // add entry 124*cdf0e10cSrcweir maEvents.push( EventEntry( rEvent, rEvent->getActivationTime( 125*cdf0e10cSrcweir mpTimer->getElapsedTime()) ) ); 126*cdf0e10cSrcweir return true; 127*cdf0e10cSrcweir } 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir bool EventQueue::addEventForNextRound( EventSharedPtr const& rEvent ) 130*cdf0e10cSrcweir { 131*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 132*cdf0e10cSrcweir 133*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS) 134*cdf0e10cSrcweir OSL_TRACE("adding at %f event [%s] at %x for next round with delay %f\r", 135*cdf0e10cSrcweir mpTimer->getElapsedTime(), 136*cdf0e10cSrcweir OUStringToOString(rEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(), 137*cdf0e10cSrcweir rEvent.get(), 138*cdf0e10cSrcweir rEvent->getActivationTime(0.0)); 139*cdf0e10cSrcweir #endif 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( rEvent.get() != NULL, 142*cdf0e10cSrcweir "EventQueue::addEvent: event ptr NULL" ); 143*cdf0e10cSrcweir maNextEvents.push_back( 144*cdf0e10cSrcweir EventEntry( rEvent, rEvent->getActivationTime( 145*cdf0e10cSrcweir mpTimer->getElapsedTime()) ) ); 146*cdf0e10cSrcweir return true; 147*cdf0e10cSrcweir } 148*cdf0e10cSrcweir 149*cdf0e10cSrcweir bool EventQueue::addEventWhenQueueIsEmpty (const EventSharedPtr& rpEvent) 150*cdf0e10cSrcweir { 151*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 152*cdf0e10cSrcweir 153*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS) 154*cdf0e10cSrcweir OSL_TRACE("adding at %f event [%s] at %x for execution when queue is empty with delay %f\r", 155*cdf0e10cSrcweir mpTimer->getElapsedTime(), 156*cdf0e10cSrcweir OUStringToOString(rpEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(), 157*cdf0e10cSrcweir rpEvent.get(), 158*cdf0e10cSrcweir rpEvent->getActivationTime(0.0)); 159*cdf0e10cSrcweir #endif 160*cdf0e10cSrcweir 161*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 162*cdf0e10cSrcweir rpEvent.get() != NULL, 163*cdf0e10cSrcweir "EventQueue::addEvent: event ptr NULL"); 164*cdf0e10cSrcweir 165*cdf0e10cSrcweir maNextNextEvents.push( 166*cdf0e10cSrcweir EventEntry( 167*cdf0e10cSrcweir rpEvent, 168*cdf0e10cSrcweir rpEvent->getActivationTime(mpTimer->getElapsedTime()))); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir return true; 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir void EventQueue::forceEmpty() 174*cdf0e10cSrcweir { 175*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 176*cdf0e10cSrcweir 177*cdf0e10cSrcweir process_(true); 178*cdf0e10cSrcweir } 179*cdf0e10cSrcweir 180*cdf0e10cSrcweir void EventQueue::process() 181*cdf0e10cSrcweir { 182*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir process_(false); 185*cdf0e10cSrcweir } 186*cdf0e10cSrcweir 187*cdf0e10cSrcweir void EventQueue::process_( bool bFireAllEvents ) 188*cdf0e10cSrcweir { 189*cdf0e10cSrcweir VERBOSE_TRACE( "EventQueue: heartbeat" ); 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir // add in all that have been added explicitly for this round: 192*cdf0e10cSrcweir EventEntryVector::const_iterator const iEnd( maNextEvents.end() ); 193*cdf0e10cSrcweir for ( EventEntryVector::const_iterator iPos( maNextEvents.begin() ); 194*cdf0e10cSrcweir iPos != iEnd; ++iPos ) { 195*cdf0e10cSrcweir maEvents.push(*iPos); 196*cdf0e10cSrcweir } 197*cdf0e10cSrcweir EventEntryVector().swap( maNextEvents ); 198*cdf0e10cSrcweir 199*cdf0e10cSrcweir // perform topmost, ready-to-execute event 200*cdf0e10cSrcweir // ======================================= 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir const double nCurrTime( mpTimer->getElapsedTime() ); 203*cdf0e10cSrcweir 204*cdf0e10cSrcweir // When maEvents does not contain any events that are due now 205*cdf0e10cSrcweir // then process one event from maNextNextEvents. 206*cdf0e10cSrcweir if (!maNextNextEvents.empty() 207*cdf0e10cSrcweir && !bFireAllEvents 208*cdf0e10cSrcweir && (maEvents.empty() || maEvents.top().nTime > nCurrTime)) 209*cdf0e10cSrcweir { 210*cdf0e10cSrcweir const EventEntry aEvent (maNextNextEvents.top()); 211*cdf0e10cSrcweir maNextNextEvents.pop(); 212*cdf0e10cSrcweir maEvents.push(aEvent); 213*cdf0e10cSrcweir } 214*cdf0e10cSrcweir 215*cdf0e10cSrcweir // process ready/elapsed events. Note that the 'perceived' 216*cdf0e10cSrcweir // current time remains constant for this loop, thus we're 217*cdf0e10cSrcweir // processing only those events which where ready when we 218*cdf0e10cSrcweir // entered this method. 219*cdf0e10cSrcweir while( !maEvents.empty() && 220*cdf0e10cSrcweir (bFireAllEvents || maEvents.top().nTime <= nCurrTime) ) 221*cdf0e10cSrcweir { 222*cdf0e10cSrcweir EventEntry event( maEvents.top() ); 223*cdf0e10cSrcweir maEvents.pop(); 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir // only process event, if it is still 'charged', 226*cdf0e10cSrcweir // i.e. the fire() call effects something. This is 227*cdf0e10cSrcweir // used when e.g. having events registered at multiple 228*cdf0e10cSrcweir // places, which should fire only once: after the 229*cdf0e10cSrcweir // initial fire() call, those events become inactive 230*cdf0e10cSrcweir // and return false on isCharged. This frees us from 231*cdf0e10cSrcweir // the need to prune queues of those inactive shells. 232*cdf0e10cSrcweir if( event.pEvent->isCharged() ) 233*cdf0e10cSrcweir { 234*cdf0e10cSrcweir try 235*cdf0e10cSrcweir { 236*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0 237*cdf0e10cSrcweir VERBOSE_TRACE( "Firing event: unknown (0x%X), timeout was: %f", 238*cdf0e10cSrcweir event.pEvent.get(), 239*cdf0e10cSrcweir event.pEvent->getActivationTime(0.0) ); 240*cdf0e10cSrcweir #endif 241*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS) 242*cdf0e10cSrcweir OSL_TRACE("firing at %f event [%s] at %x with delay %f\r", 243*cdf0e10cSrcweir mpTimer->getElapsedTime(), 244*cdf0e10cSrcweir OUStringToOString(event.pEvent->GetDescription(), 245*cdf0e10cSrcweir RTL_TEXTENCODING_UTF8).getStr(), 246*cdf0e10cSrcweir event.pEvent.get(), 247*cdf0e10cSrcweir event.pEvent->getActivationTime(0.0)); 248*cdf0e10cSrcweir #endif 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir event.pEvent->fire(); 251*cdf0e10cSrcweir } 252*cdf0e10cSrcweir catch( uno::RuntimeException& ) 253*cdf0e10cSrcweir { 254*cdf0e10cSrcweir throw; 255*cdf0e10cSrcweir } 256*cdf0e10cSrcweir catch( uno::Exception& ) 257*cdf0e10cSrcweir { 258*cdf0e10cSrcweir // catch anything here, we don't want 259*cdf0e10cSrcweir // to leave this scope under _any_ 260*cdf0e10cSrcweir // circumstance. Although, do _not_ 261*cdf0e10cSrcweir // reinsert an activity that threw 262*cdf0e10cSrcweir // once. 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir // NOTE: we explicitely don't catch(...) here, 265*cdf0e10cSrcweir // since this will also capture segmentation 266*cdf0e10cSrcweir // violations and the like. In such a case, we 267*cdf0e10cSrcweir // still better let our clients now... 268*cdf0e10cSrcweir OSL_ENSURE( false, 269*cdf0e10cSrcweir rtl::OUStringToOString( 270*cdf0e10cSrcweir comphelper::anyToString( cppu::getCaughtException() ), 271*cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 272*cdf0e10cSrcweir } 273*cdf0e10cSrcweir catch( SlideShowException& ) 274*cdf0e10cSrcweir { 275*cdf0e10cSrcweir // catch anything here, we don't want 276*cdf0e10cSrcweir // to leave this scope under _any_ 277*cdf0e10cSrcweir // circumstance. Although, do _not_ 278*cdf0e10cSrcweir // reinsert an activity that threw 279*cdf0e10cSrcweir // once. 280*cdf0e10cSrcweir 281*cdf0e10cSrcweir // NOTE: we explicitely don't catch(...) here, 282*cdf0e10cSrcweir // since this will also capture segmentation 283*cdf0e10cSrcweir // violations and the like. In such a case, we 284*cdf0e10cSrcweir // still better let our clients now... 285*cdf0e10cSrcweir OSL_TRACE( "::presentation::internal::EventQueue: Event threw a SlideShowException, action might not have been fully performed" ); 286*cdf0e10cSrcweir } 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir else 289*cdf0e10cSrcweir { 290*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0 291*cdf0e10cSrcweir VERBOSE_TRACE( "Ignoring discharged event: unknown (0x%X), timeout was: %f", 292*cdf0e10cSrcweir event.pEvent.get(), 293*cdf0e10cSrcweir event.pEvent->getActivationTime(0.0) ); 294*cdf0e10cSrcweir #endif 295*cdf0e10cSrcweir } 296*cdf0e10cSrcweir } 297*cdf0e10cSrcweir } 298*cdf0e10cSrcweir 299*cdf0e10cSrcweir bool EventQueue::isEmpty() const 300*cdf0e10cSrcweir { 301*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 302*cdf0e10cSrcweir 303*cdf0e10cSrcweir return maEvents.empty() && maNextEvents.empty() && maNextNextEvents.empty(); 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir double EventQueue::nextTimeout() const 307*cdf0e10cSrcweir { 308*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 309*cdf0e10cSrcweir 310*cdf0e10cSrcweir // return time for next entry (if any) 311*cdf0e10cSrcweir double nTimeout (::std::numeric_limits<double>::max()); 312*cdf0e10cSrcweir const double nCurrentTime (mpTimer->getElapsedTime()); 313*cdf0e10cSrcweir if ( ! maEvents.empty()) 314*cdf0e10cSrcweir nTimeout = maEvents.top().nTime - nCurrentTime; 315*cdf0e10cSrcweir if ( ! maNextEvents.empty()) 316*cdf0e10cSrcweir nTimeout = ::std::min(nTimeout, maNextEvents.front().nTime - nCurrentTime); 317*cdf0e10cSrcweir if ( ! maNextNextEvents.empty()) 318*cdf0e10cSrcweir nTimeout = ::std::min(nTimeout, maNextNextEvents.top().nTime - nCurrentTime); 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir return nTimeout; 321*cdf0e10cSrcweir } 322*cdf0e10cSrcweir 323*cdf0e10cSrcweir void EventQueue::clear() 324*cdf0e10cSrcweir { 325*cdf0e10cSrcweir ::osl::MutexGuard aGuard( maMutex ); 326*cdf0e10cSrcweir 327*cdf0e10cSrcweir // TODO(P1): Maybe a plain vector and vector.swap will 328*cdf0e10cSrcweir // be faster here. Profile. 329*cdf0e10cSrcweir maEvents = ImplQueueType(); 330*cdf0e10cSrcweir 331*cdf0e10cSrcweir maNextEvents.clear(); 332*cdf0e10cSrcweir maNextNextEvents = ImplQueueType(); 333*cdf0e10cSrcweir } 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir } 336