update dev300-m58
[ooovba.git] / sdext / source / presenter / PresenterTimer.cxx
blobc29e3b9c7ef91bd227fb5abc94d710d8874ea7a7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PresenterTimer.cxx,v $
11 * $Revision: 1.4 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_sdext.hxx"
35 #include "PresenterTimer.hxx"
36 #include <osl/doublecheckedlocking.h>
37 #include <osl/thread.hxx>
38 #include <boost/bind.hpp>
39 #include <boost/function.hpp>
40 #include <boost/enable_shared_from_this.hpp>
41 #include <set>
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
46 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
48 namespace sdext { namespace presenter {
50 namespace {
51 class TimerTask
53 public:
54 TimerTask (
55 const PresenterTimer::Task& rTask,
56 const TimeValue& rDueTime,
57 const sal_Int64 nRepeatIntervall,
58 const sal_Int32 nTaskId);
59 ~TimerTask (void) {}
61 PresenterTimer::Task maTask;
62 TimeValue maDueTime;
63 const sal_Int64 mnRepeatIntervall;
64 const sal_Int32 mnTaskId;
65 bool mbIsCanceled;
68 typedef ::boost::shared_ptr<TimerTask> SharedTimerTask;
71 /** Queue all scheduled tasks and process them when their time has come.
73 class TimerScheduler
74 : public ::boost::enable_shared_from_this<TimerScheduler>,
75 public ::osl::Thread
77 public:
78 static ::boost::shared_ptr<TimerScheduler> Instance (void);
79 static SharedTimerTask CreateTimerTask (
80 const PresenterTimer::Task& rTask,
81 const TimeValue& rDueTime,
82 const sal_Int64 nRepeatIntervall);
84 void ScheduleTask (const SharedTimerTask& rpTask);
85 void CancelTask (const sal_Int32 nTaskId);
87 static bool GetCurrentTime (TimeValue& rCurrentTime);
88 static sal_Int64 GetTimeDifference (
89 const TimeValue& rTargetTime,
90 const TimeValue& rCurrentTime);
91 static void ConvertToTimeValue (
92 TimeValue& rTimeValue,
93 const sal_Int64 nTimeDifference);
94 static sal_Int64 ConvertFromTimeValue (
95 const TimeValue& rTimeValue);
97 private:
98 static ::boost::shared_ptr<TimerScheduler> mpInstance;
99 static ::osl::Mutex maInstanceMutex;
100 static sal_Int32 mnTaskId;
102 ::osl::Mutex maTaskContainerMutex;
103 typedef ::std::set<SharedTimerTask> TaskContainer;
104 TaskContainer maScheduledTasks;
105 bool mbIsRunning;
106 ::osl::Mutex maCurrentTaskMutex;
107 SharedTimerTask mpCurrentTask;
109 static void Release (void);
111 TimerScheduler (void);
112 virtual ~TimerScheduler (void);
113 class Deleter {public: void operator () (TimerScheduler* pScheduler) { delete pScheduler; } };
114 friend class Deleter;
116 virtual void SAL_CALL run (void);
117 virtual void SAL_CALL onTerminated (void);
123 bool GetDateTime (oslDateTime& rDateTime);
124 } // end of anonymous namespace
127 //===== PresenterTimer ========================================================
129 sal_Int32 PresenterTimer::ScheduleSingleTaskRelative (
130 const Task& rTask,
131 const sal_Int64 nDelay)
133 return ScheduleRepeatedTask(rTask, nDelay, 0);
139 sal_Int32 PresenterTimer::ScheduleSingleTaskAbsolute (
140 const Task& rTask,
141 const TimeValue& rDueTime)
143 SharedTimerTask pTask (TimerScheduler::CreateTimerTask(rTask, rDueTime, 0));
144 TimerScheduler::Instance()->ScheduleTask(pTask);
145 return pTask->mnTaskId;
151 sal_Int32 PresenterTimer::ScheduleRepeatedTask (
152 const Task& rTask,
153 const sal_Int64 nDelay,
154 const sal_Int64 nIntervall)
156 TimeValue aCurrentTime;
157 if (TimerScheduler::GetCurrentTime(aCurrentTime))
159 TimeValue aDueTime;
160 TimerScheduler::ConvertToTimeValue(
161 aDueTime,
162 TimerScheduler::ConvertFromTimeValue (aCurrentTime) + nDelay);
163 SharedTimerTask pTask (TimerScheduler::CreateTimerTask(rTask, aDueTime, nIntervall));
164 TimerScheduler::Instance()->ScheduleTask(pTask);
165 return pTask->mnTaskId;
168 return NotAValidTaskId;
174 void PresenterTimer::CancelTask (const sal_Int32 nTaskId)
176 return TimerScheduler::Instance()->CancelTask(nTaskId);
182 //===== TimerScheduler ========================================================
184 ::boost::shared_ptr<TimerScheduler> TimerScheduler::mpInstance;
185 ::osl::Mutex TimerScheduler::maInstanceMutex;
186 sal_Int32 TimerScheduler::mnTaskId = PresenterTimer::NotAValidTaskId;
188 ::boost::shared_ptr<TimerScheduler> TimerScheduler::Instance (void)
190 ::boost::shared_ptr<TimerScheduler> pInstance = mpInstance;
191 if (pInstance.get() == NULL)
193 ::osl::MutexGuard aGuard (maInstanceMutex);
194 pInstance = mpInstance;
195 if (pInstance.get() == NULL)
197 pInstance.reset(new TimerScheduler(), TimerScheduler::Deleter());
198 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
199 mpInstance = pInstance;
202 else
204 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
206 return pInstance;
212 void TimerScheduler::Release (void)
214 ::osl::MutexGuard aGuard (maInstanceMutex);
215 mpInstance.reset();
221 TimerScheduler::TimerScheduler (void)
222 : maTaskContainerMutex(),
223 maScheduledTasks(),
224 mbIsRunning(false),
225 maCurrentTaskMutex(),
226 mpCurrentTask()
233 TimerScheduler::~TimerScheduler (void)
239 SharedTimerTask TimerScheduler::CreateTimerTask (
240 const PresenterTimer::Task& rTask,
241 const TimeValue& rDueTime,
242 const sal_Int64 nRepeatIntervall)
244 return SharedTimerTask(new TimerTask(rTask, rDueTime, nRepeatIntervall, ++mnTaskId));
250 void TimerScheduler::ScheduleTask (const SharedTimerTask& rpTask)
252 if (rpTask.get() == NULL)
253 return;
254 if (rpTask->mbIsCanceled)
255 return;
257 osl::MutexGuard aGuard (maTaskContainerMutex);
258 maScheduledTasks.insert(rpTask);
260 if ( ! mbIsRunning)
262 mbIsRunning = true;
263 create();
270 void TimerScheduler::CancelTask (const sal_Int32 nTaskId)
272 // Set of scheduled tasks is sorted after their due times, not their
273 // task ids. Therefore we have to do a linear search for the task to
274 // cancel.
276 ::osl::MutexGuard aGuard (maTaskContainerMutex);
277 TaskContainer::iterator iTask (maScheduledTasks.begin());
278 TaskContainer::const_iterator iEnd (maScheduledTasks.end());
279 for ( ; iTask!=iEnd; ++iTask)
281 if ((*iTask)->mnTaskId == nTaskId)
283 maScheduledTasks.erase(iTask);
284 break;
289 // The task that is to be canceled may be currently about to be
290 // processed. Mark it with a flag that a) prevents a repeating task
291 // from being scheduled again and b) tries to prevent its execution.
292 if (mpCurrentTask.get() != NULL
293 && mpCurrentTask->mnTaskId == nTaskId)
295 mpCurrentTask->mbIsCanceled = true;
298 // When the last active task was canceled then the timer can be
299 // stopped.
300 if (maScheduledTasks.size() == 0)
302 mbIsRunning = false;
303 resume();
304 // join();
311 void SAL_CALL TimerScheduler::run (void)
313 while (mbIsRunning)
315 // Get the current time.
316 TimeValue aCurrentTime;
317 if ( ! GetCurrentTime(aCurrentTime))
319 // We can not get the current time and thus can not schedule anything.
320 break;
323 // Restrict access to the maScheduledTasks member to one, mutext
324 // guarded, block.
325 SharedTimerTask pTask;
326 sal_Int64 nDifference = 0;
328 ::osl::MutexGuard aGuard (maTaskContainerMutex);
330 // There are no more scheduled task. Leave this loop, function and
331 // live of the TimerScheduler.
332 if (maScheduledTasks.empty())
333 break;
335 nDifference = GetTimeDifference(
336 (*maScheduledTasks.begin())->maDueTime,
337 aCurrentTime);
338 if (nDifference <= 0)
340 pTask = *maScheduledTasks.begin();
341 maScheduledTasks.erase(maScheduledTasks.begin());
345 // Acquire a reference to the current task.
347 ::osl::MutexGuard aGuard (maCurrentTaskMutex);
348 mpCurrentTask = pTask;
351 if (mpCurrentTask.get() == NULL)
353 // Wait until the first task becomes due.
354 TimeValue aTimeValue;
355 ConvertToTimeValue(aTimeValue, nDifference);
356 wait(aTimeValue);
358 else
360 // Execute task.
361 if ( ! mpCurrentTask->maTask.empty()
362 && ! mpCurrentTask->mbIsCanceled)
364 mpCurrentTask->maTask(aCurrentTime);
366 // Re-schedule repeating tasks.
367 if (mpCurrentTask->mnRepeatIntervall > 0)
369 ConvertToTimeValue(
370 mpCurrentTask->maDueTime,
371 ConvertFromTimeValue(mpCurrentTask->maDueTime)
372 + mpCurrentTask->mnRepeatIntervall);
373 ScheduleTask(mpCurrentTask);
379 // Release reference to the current task.
381 ::osl::MutexGuard aGuard (maCurrentTaskMutex);
382 mpCurrentTask.reset();
390 void SAL_CALL TimerScheduler::onTerminated (void)
392 Release();
398 bool TimerScheduler::GetCurrentTime (TimeValue& rCurrentTime)
400 TimeValue aSystemTime;
401 if (osl_getSystemTime(&aSystemTime))
402 return osl_getLocalTimeFromSystemTime(&aSystemTime, &rCurrentTime);
403 return false;
409 sal_Int64 TimerScheduler::GetTimeDifference (
410 const TimeValue& rTargetTime,
411 const TimeValue& rCurrentTime)
413 return ConvertFromTimeValue(rTargetTime) - ConvertFromTimeValue(rCurrentTime);
419 void TimerScheduler::ConvertToTimeValue (
420 TimeValue& rTimeValue,
421 const sal_Int64 nTimeDifference)
423 rTimeValue.Seconds = sal::static_int_cast<sal_Int32>(nTimeDifference / 1000000000L);
424 rTimeValue.Nanosec = sal::static_int_cast<sal_Int32>(nTimeDifference % 1000000000L);
430 sal_Int64 TimerScheduler::ConvertFromTimeValue (
431 const TimeValue& rTimeValue)
433 return sal_Int64(rTimeValue.Seconds) * 1000000000L + rTimeValue.Nanosec;
439 //===== TimerTask =============================================================
441 namespace {
443 TimerTask::TimerTask (
444 const PresenterTimer::Task& rTask,
445 const TimeValue& rDueTime,
446 const sal_Int64 nRepeatIntervall,
447 const sal_Int32 nTaskId)
448 : maTask(rTask),
449 maDueTime(rDueTime),
450 mnRepeatIntervall(nRepeatIntervall),
451 mnTaskId(nTaskId),
452 mbIsCanceled(false)
456 } // end of anonymous namespace
461 //===== PresenterTimer ========================================================
464 ::rtl::Reference<PresenterClockTimer> PresenterClockTimer::mpInstance;
466 ::rtl::Reference<PresenterClockTimer> PresenterClockTimer::Instance (
467 const css::uno::Reference<css::uno::XComponentContext>& rxContext)
469 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
471 ::rtl::Reference<PresenterClockTimer> pTimer;
472 if (mpInstance.is())
474 pTimer = mpInstance;
476 if ( ! pTimer.is())
478 pTimer = ::rtl::Reference<PresenterClockTimer>(new PresenterClockTimer(rxContext));
479 mpInstance = pTimer;
481 return pTimer;
487 PresenterClockTimer::PresenterClockTimer (const Reference<XComponentContext>& rxContext)
488 : PresenterClockTimerInterfaceBase(m_aMutex),
489 maListeners(),
490 maDateTime(),
491 mnTimerTaskId(PresenterTimer::NotAValidTaskId),
492 mbIsCallbackPending(false),
493 mxRequestCallback()
495 Reference<lang::XMultiComponentFactory> xFactory (
496 rxContext->getServiceManager(), UNO_QUERY);
497 if (xFactory.is())
498 mxRequestCallback = Reference<awt::XRequestCallback>(
499 xFactory->createInstanceWithContext(
500 A2S("com.sun.star.awt.AsyncCallback"),
501 rxContext),
502 UNO_QUERY_THROW);
508 PresenterClockTimer::~PresenterClockTimer (void)
510 if (mnTimerTaskId != PresenterTimer::NotAValidTaskId)
512 PresenterTimer::CancelTask(mnTimerTaskId);
513 mnTimerTaskId = PresenterTimer::NotAValidTaskId;
516 Reference<lang::XComponent> xComponent (mxRequestCallback, UNO_QUERY);
517 if (xComponent.is())
518 xComponent->dispose();
519 mxRequestCallback = NULL;
525 void PresenterClockTimer::AddListener (const SharedListener& rListener)
527 osl::MutexGuard aGuard (maMutex);
529 maListeners.push_back(rListener);
531 // Create a timer task when the first listener is added.
532 if (mnTimerTaskId==PresenterTimer::NotAValidTaskId)
534 mnTimerTaskId = PresenterTimer::ScheduleRepeatedTask(
535 ::boost::bind(&PresenterClockTimer::CheckCurrentTime, this, _1),
537 250000000 /*ns*/);
544 void PresenterClockTimer::RemoveListener (const SharedListener& rListener)
546 osl::MutexGuard aGuard (maMutex);
548 ListenerContainer::iterator iListener (::std::find(
549 maListeners.begin(),
550 maListeners.end(),
551 rListener));
552 if (iListener != maListeners.end())
553 maListeners.erase(iListener);
554 if (maListeners.size() == 0)
556 // We have no more clients and therefore are not interested in time changes.
557 if (mnTimerTaskId != PresenterTimer::NotAValidTaskId)
559 PresenterTimer::CancelTask(mnTimerTaskId);
560 mnTimerTaskId = PresenterTimer::NotAValidTaskId;
562 mpInstance = NULL;
569 oslDateTime PresenterClockTimer::GetCurrentTime (void)
571 TimeValue aCurrentTime;
572 TimerScheduler::GetCurrentTime(aCurrentTime);
573 oslDateTime aDateTime;
574 osl_getDateTimeFromTimeValue(&aCurrentTime, &aDateTime);
575 return aDateTime;
581 sal_Int64 PresenterClockTimer::GetTimeDifference (
582 const oslDateTime& rNow,
583 const oslDateTime& rThen)
585 TimeValue aNow;
586 TimeValue aThen;
587 if (osl_getTimeValueFromDateTime(const_cast<oslDateTime*>(&rNow),&aNow)
588 && osl_getTimeValueFromDateTime(const_cast<oslDateTime*>(&rThen),&aThen))
590 return TimerScheduler::GetTimeDifference(aNow, aThen);
592 else
593 return -1;
599 void PresenterClockTimer::CheckCurrentTime (const TimeValue& rCurrentTime)
601 css::uno::Reference<css::awt::XRequestCallback> xRequestCallback;
602 css::uno::Reference<css::awt::XCallback> xCallback;
604 osl::MutexGuard aGuard (maMutex);
606 TimeValue aCurrentTime (rCurrentTime);
607 oslDateTime aDateTime;
608 if (osl_getDateTimeFromTimeValue(&aCurrentTime, &aDateTime))
610 if (aDateTime.Seconds != maDateTime.Seconds
611 || aDateTime.Minutes != maDateTime.Minutes
612 || aDateTime.Seconds != maDateTime.Seconds)
614 // The displayed part of the current time has changed.
615 // Prepare to call the listeners.
616 maDateTime = aDateTime;
618 // Schedule notification of listeners.
619 if (mxRequestCallback.is() && ! mbIsCallbackPending)
621 mbIsCallbackPending = true;
622 xRequestCallback = mxRequestCallback;
623 xCallback = this;
628 if (mxRequestCallback.is() && xCallback.is())
629 xRequestCallback->addCallback(xCallback, Any());
635 //----- XCallback -------------------------------------------------------------
637 void SAL_CALL PresenterClockTimer::notify (const css::uno::Any& rUserData)
638 throw (css::uno::RuntimeException)
640 (void)rUserData;
642 ListenerContainer aListenerCopy (maListeners);
645 osl::MutexGuard aGuard (maMutex);
647 mbIsCallbackPending = false;
649 ::std::copy(
650 maListeners.begin(),
651 maListeners.end(),
652 ::std::back_inserter(aListenerCopy));
655 if (aListenerCopy.size() > 0)
657 ListenerContainer::const_iterator iListener;
658 ListenerContainer::const_iterator iEnd (aListenerCopy.end());
659 for (iListener=aListenerCopy.begin(); iListener!=iEnd; ++iListener)
661 (*iListener)->TimeHasChanged(maDateTime);
668 } } // end of namespace ::sdext::presenter