1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PresenterTimer.cxx,v $
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>
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
{
55 const PresenterTimer::Task
& rTask
,
56 const TimeValue
& rDueTime
,
57 const sal_Int64 nRepeatIntervall
,
58 const sal_Int32 nTaskId
);
61 PresenterTimer::Task maTask
;
63 const sal_Int64 mnRepeatIntervall
;
64 const sal_Int32 mnTaskId
;
68 typedef ::boost::shared_ptr
<TimerTask
> SharedTimerTask
;
71 /** Queue all scheduled tasks and process them when their time has come.
74 : public ::boost::enable_shared_from_this
<TimerScheduler
>,
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
);
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
;
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 (
131 const sal_Int64 nDelay
)
133 return ScheduleRepeatedTask(rTask
, nDelay
, 0);
139 sal_Int32
PresenterTimer::ScheduleSingleTaskAbsolute (
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 (
153 const sal_Int64 nDelay
,
154 const sal_Int64 nIntervall
)
156 TimeValue aCurrentTime
;
157 if (TimerScheduler::GetCurrentTime(aCurrentTime
))
160 TimerScheduler::ConvertToTimeValue(
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
;
204 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
212 void TimerScheduler::Release (void)
214 ::osl::MutexGuard
aGuard (maInstanceMutex
);
221 TimerScheduler::TimerScheduler (void)
222 : maTaskContainerMutex(),
225 maCurrentTaskMutex(),
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
)
254 if (rpTask
->mbIsCanceled
)
257 osl::MutexGuard
aGuard (maTaskContainerMutex
);
258 maScheduledTasks
.insert(rpTask
);
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
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
);
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
300 if (maScheduledTasks
.size() == 0)
311 void SAL_CALL
TimerScheduler::run (void)
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.
323 // Restrict access to the maScheduledTasks member to one, mutext
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())
335 nDifference
= GetTimeDifference(
336 (*maScheduledTasks
.begin())->maDueTime
,
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
);
361 if ( ! mpCurrentTask
->maTask
.empty()
362 && ! mpCurrentTask
->mbIsCanceled
)
364 mpCurrentTask
->maTask(aCurrentTime
);
366 // Re-schedule repeating tasks.
367 if (mpCurrentTask
->mnRepeatIntervall
> 0)
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)
398 bool TimerScheduler::GetCurrentTime (TimeValue
& rCurrentTime
)
400 TimeValue aSystemTime
;
401 if (osl_getSystemTime(&aSystemTime
))
402 return osl_getLocalTimeFromSystemTime(&aSystemTime
, &rCurrentTime
);
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 =============================================================
443 TimerTask::TimerTask (
444 const PresenterTimer::Task
& rTask
,
445 const TimeValue
& rDueTime
,
446 const sal_Int64 nRepeatIntervall
,
447 const sal_Int32 nTaskId
)
450 mnRepeatIntervall(nRepeatIntervall
),
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
;
478 pTimer
= ::rtl::Reference
<PresenterClockTimer
>(new PresenterClockTimer(rxContext
));
487 PresenterClockTimer::PresenterClockTimer (const Reference
<XComponentContext
>& rxContext
)
488 : PresenterClockTimerInterfaceBase(m_aMutex
),
491 mnTimerTaskId(PresenterTimer::NotAValidTaskId
),
492 mbIsCallbackPending(false),
495 Reference
<lang::XMultiComponentFactory
> xFactory (
496 rxContext
->getServiceManager(), UNO_QUERY
);
498 mxRequestCallback
= Reference
<awt::XRequestCallback
>(
499 xFactory
->createInstanceWithContext(
500 A2S("com.sun.star.awt.AsyncCallback"),
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
);
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
),
544 void PresenterClockTimer::RemoveListener (const SharedListener
& rListener
)
546 osl::MutexGuard
aGuard (maMutex
);
548 ListenerContainer::iterator
iListener (::std::find(
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
;
569 oslDateTime
PresenterClockTimer::GetCurrentTime (void)
571 TimeValue aCurrentTime
;
572 TimerScheduler::GetCurrentTime(aCurrentTime
);
573 oslDateTime aDateTime
;
574 osl_getDateTimeFromTimeValue(&aCurrentTime
, &aDateTime
);
581 sal_Int64
PresenterClockTimer::GetTimeDifference (
582 const oslDateTime
& rNow
,
583 const oslDateTime
& rThen
)
587 if (osl_getTimeValueFromDateTime(const_cast<oslDateTime
*>(&rNow
),&aNow
)
588 && osl_getTimeValueFromDateTime(const_cast<oslDateTime
*>(&rThen
),&aThen
))
590 return TimerScheduler::GetTimeDifference(aNow
, aThen
);
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
;
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
)
642 ListenerContainer
aListenerCopy (maListeners
);
645 osl::MutexGuard
aGuard (maMutex
);
647 mbIsCallbackPending
= false;
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