1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Moonlight List (moonlight-list@lists.ximian.com)
6 * Copyright 2007 Novell, Inc. (http://www.novell.com)
8 * See the LICENSE file included with the distribution for details.
16 #include "timemanager.h"
17 #include "timesource.h"
20 #define PUT_TIME_MANAGER_TO_SLEEP 0
23 #define STARTTICKTIMER(id,str) STARTTIMER(id,str)
24 #define ENDTICKTIMER(id,str) ENDTIMER(id,str)
26 #define STARTTICKTIMER(id,str)
27 #define ENDTICKTIMER(id,str)
32 #define DEFAULT_FPS 50
33 #define MAXIMUM_FPS 50
35 #define FPS_TO_DELAY(fps) (int)(((double)1/(fps)) * 1000)
36 #define DELAY_TO_FPS(delay) (1000.0 / delay)
38 class TickCall
: public List::Node
{
42 TickCall (TickCallHandler func
, EventObject
*data
)
57 class RootClockGroup
: public ClockGroup
60 RootClockGroup (TimelineGroup
*timeline
) : ClockGroup (timeline
, true) { }
62 virtual bool UpdateFromParentTime (TimeSpan parentTime
)
64 bool rv
= Clock::UpdateFromParentTime (parentTime
);
66 bool children_rv
= false;
67 for (GList
*l
= child_clocks
; l
; l
= l
->next
) {
68 Clock
*clock
= (Clock
*)l
->data
;
69 children_rv
= clock
->UpdateFromParentTime (current_time
) || children_rv
;
72 return rv
&& children_rv
;
76 virtual ~RootClockGroup () { }
79 TimeManager::TimeManager ()
81 SetObjectType (Type::TIMEMANAGER
);
83 if (moonlight_flags
& RUNTIME_INIT_MANUAL_TIMESOURCE
)
84 source
= new ManualTimeSource();
86 source
= new SystemTimeSource(Deployment::GetCurrent ());
88 current_timeout
= FPS_TO_DELAY (DEFAULT_FPS
); /* something suitably small */
89 max_fps
= MAXIMUM_FPS
;
90 flags
= (TimeManagerOp
) (TIME_MANAGER_UPDATE_CLOCKS
| TIME_MANAGER_RENDER
| TIME_MANAGER_TICK_CALL
/*| TIME_MANAGER_UPDATE_INPUT*/);
92 start_time
= source
->GetNow ();
93 start_time_usec
= start_time
/ 10;
94 source
->AddHandler (TimeSource::TickEvent
, source_tick_callback
, this);
96 registered_timeouts
= NULL
;
97 source_tick_pending
= false;
101 applier
= new Applier ();
103 timeline
= new ParallelTimeline();
104 timeline
->SetDuration (Duration::Forever
);
105 root_clock
= new RootClockGroup (timeline
);
106 char *name
= g_strdup_printf ("Surface clock group for time manager (%p)", this);
107 root_clock
->SetValue(DependencyObject::NameProperty
, name
);
109 root_clock
->SetTimeManager (this);
112 TimeManager::~TimeManager ()
114 source
->RemoveHandler (TimeSource::TickEvent
, source_tick_callback
, this);
118 root_clock
->Dispose ();
123 root_clock
->unref ();
129 RemoveAllRegisteredTimeouts ();
133 TimeManager::SetMaximumRefreshRate (int hz
)
139 current_timeout
= FPS_TO_DELAY (hz
);
140 source
->SetTimerFrequency (current_timeout
);
147 last_global_time
= current_global_time
= source
->GetNow();
148 current_global_time_usec
= current_global_time
/ 10;
149 source
->SetTimerFrequency (current_timeout
);
151 source_tick_pending
= true;
161 TimeManager::Shutdown ()
163 RemoveAllRegisteredTimeouts ();
168 TimeManager::source_tick_callback (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
170 ((TimeManager
*) closure
)->SourceTick ();
174 TimeManager::InvokeTickCalls ()
178 while ((call
= (TickCall
*) tick_calls
.Pop ())) {
179 call
->func (call
->data
);
182 dispatcher_calls
.Lock ();
184 dispatcher_calls
.MoveTo (tick_calls
);
185 dispatcher_calls
.Unlock ();
189 TimeManager::AddTimeout (gint priority
, guint ms_interval
, GSourceFunc func
, gpointer tick_data
)
191 guint rv
= g_timeout_add_full (priority
, ms_interval
, func
, tick_data
, NULL
);
192 registered_timeouts
= g_list_prepend (registered_timeouts
, GUINT_TO_POINTER (rv
));
197 TimeManager::RemoveTimeout (guint timeout_id
)
199 g_source_remove (timeout_id
);
200 registered_timeouts
= g_list_remove_all (registered_timeouts
, GUINT_TO_POINTER (timeout_id
));
204 TimeManager::RemoveAllRegisteredTimeouts ()
207 for (t
= registered_timeouts
; t
; t
= t
->next
)
208 g_source_remove (GPOINTER_TO_UINT (t
->data
));
210 g_list_free (registered_timeouts
);
211 registered_timeouts
= NULL
;
215 TimeManager::AddTickCall (TickCallHandler func
, EventObject
*tick_data
)
217 tick_calls
.Push (new TickCall (func
, tick_data
));
219 #if PUT_TIME_MANAGER_TO_SLEEP
220 flags
= (TimeManagerOp
)(flags
| TIME_MANAGER_TICK_CALL
);
221 if (!source_tick_pending
) {
222 source_tick_pending
= true;
223 source
->SetTimerFrequency (current_timeout
);
229 struct TickCallFindData
{
230 TickCallHandler func
;
235 TimeManager::RemoveTickCall (TickCallHandler func
, EventObject
*tick_data
)
244 List::Node
* call
= tick_calls
.LinkedList ()->Find (find_tick_call
, &fd
);
246 tick_calls
.LinkedList ()->Remove (call
);
247 #if PUT_TIME_MANAGER_TO_SLEEP
248 if (tick_calls
.IsEmpty()) {
249 flags
= (TimeManagerOp
)(flags
& ~TIME_MANAGER_TICK_CALL
);
250 if (flags
== 0 && source_tick_pending
)
254 tick_calls
.Unlock ();
258 TimeManager::AddDispatcherCall (TickCallHandler func
, EventObject
*tick_data
)
260 dispatcher_calls
.Lock ();
262 dispatcher_calls
.LinkedList ()->Append (new TickCall (func
, tick_data
));
264 tick_calls
.Push (new TickCall (func
, tick_data
));
265 dispatcher_calls
.Unlock ();
267 #if PUT_TIME_MANAGER_TO_SLEEP
268 flags
= (TimeManagerOp
)(flags
| TIME_MANAGER_TICK_CALL
);
269 if (!source_tick_pending
) {
270 source_tick_pending
= true;
271 source
->SetTimerFrequency (current_timeout
);
279 find_tick_call (List::Node
*node
, void *data
)
281 TickCall
*tc
= (TickCall
*)node
;
282 TickCallFindData
*fd
= (TickCallFindData
*)data
;
284 return (tc
->func
== fd
->func
&&
285 tc
->data
== fd
->data
);
289 TimeManager::NeedRedraw ()
291 #if PUT_TIME_MANAGER_TO_SLEEP
292 flags
= (TimeManagerOp
)(flags
| TIME_MANAGER_RENDER
);
293 if (!source_tick_pending
) {
294 source_tick_pending
= true;
295 source
->SetTimerFrequency (current_timeout
);
302 TimeManager::NeedClockTick ()
304 #if PUT_TIME_MANAGER_TO_SLEEP
305 flags
= (TimeManagerOp
)(flags
| TIME_MANAGER_UPDATE_CLOCKS
);
306 if (!source_tick_pending
) {
307 source_tick_pending
= true;
308 source
->SetTimerFrequency (current_timeout
);
318 while (n
--) putchar (' ');
322 output_clock (Clock
*clock
, int level
)
325 printf (clock
->Is(Type::CLOCKGROUP
) ? "ClockGroup " : "Clock ");
326 printf ("(%p) ", clock
);
327 if (clock
->GetName ()) {
328 printf ("'%s' ", clock
->GetName());
331 // getting the natural duration here upsets the clock, so let's not
332 // printf ("%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " (%.2f) ", clock->GetCurrentTime(), clock->GetNaturalDuration().GetTimeSpan(), clock->GetCurrentProgress());
333 printf ("%" G_GINT64_FORMAT
" (%.2f) ", clock
->GetCurrentTime(), clock
->GetCurrentProgress());
335 printf ("%" G_GINT64_FORMAT
" ", clock
->GetTimeline()->GetBeginTime());
337 switch (clock
->GetClockState()) {
349 if (clock
->GetIsPaused())
350 printf (" (paused)");
354 if (clock
->Is(Type::CLOCKGROUP
)) {
355 ClockGroup
*cg
= (ClockGroup
*)clock
;
357 for (GList
*l
= cg
->child_clocks
; l
; l
= l
->next
) {
358 // if (((Clock*)l->data)->GetClockState () != Clock::Stopped)
359 output_clock ((Clock
*)l
->data
, level
);
365 TimeManager::ListClocks()
367 printf ("Currently registered clocks:\n");
368 printf ("============================\n");
370 output_clock (root_clock
, 2);
372 printf ("============================\n");
376 TimeManager::AddClock (Clock
*clock
)
378 root_clock
->AddChild (clock
);
380 // we delay starting the surface's ClockGroup until the first
381 // child has been added. otherwise we run into timing issues
382 // between timelines that explicitly set a BeginTime and those
383 // that don't (and so default to 00:00:00).
384 if (root_clock
->GetClockState() != Clock::Active
)
385 root_clock
->Begin (GetCurrentTime());
391 TimeManager::SourceTick ()
393 TimeManagerOp current_flags
= flags
;
395 #if PUT_TIME_MANAGER_TO_SLEEP
396 flags
= (TimeManagerOp
)0;
399 if (current_flags
& TIME_MANAGER_TICK_CALL
) {
400 STARTTICKTIMER (tm_tick_call
, "TimeManager::Tick - Call");
402 ENDTICKTIMER (tm_tick_call
, "TimeManager::Tick - Call");
405 if (current_flags
& TIME_MANAGER_UPDATE_CLOCKS
) {
406 STARTTICKTIMER (tick_update_clocks
, "TimeManager::Tick - UpdateClocks");
407 current_global_time
= source
->GetNow();
408 current_global_time_usec
= current_global_time
/ 10;
410 bool need_another_tick
= root_clock
->UpdateFromParentTime (GetCurrentTime());
412 if (need_another_tick
)
415 // ... then cause all clocks to raise the events they've queued up
416 root_clock
->RaiseAccumulatedEvents ();
421 root_clock
->RaiseAccumulatedCompleted ();
426 ENDTICKTIMER (tick_update_clocks
, "TimeManager::Tick - UpdateClocks");
429 if (current_flags
& TIME_MANAGER_UPDATE_INPUT
) {
430 STARTTICKTIMER (tick_input
, "TimeManager::Tick - Input");
431 Emit (UpdateInputEvent
);
432 ENDTICKTIMER (tick_input
, "TimeManager::Tick - Input");
435 if (current_flags
& TIME_MANAGER_RENDER
) {
436 // fprintf (stderr, "rendering\n"); fflush (stderr);
437 STARTTICKTIMER (tick_render
, "TimeManager::Tick - Render");
438 Emit (RenderEvent
, new RenderingEventArgs (get_now()));
439 ENDTICKTIMER (tick_render
, "TimeManager::Tick - Render");
442 last_global_time
= current_global_time
;