2009-12-01 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / timemanager.cpp
blob47b7c518670216dee44fc1a7e5e5a01a529a3fbc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Contact:
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.
9 *
12 #include <config.h>
14 #include "clock.h"
15 #include "timeline.h"
16 #include "timemanager.h"
17 #include "timesource.h"
18 #include "runtime.h"
20 #define PUT_TIME_MANAGER_TO_SLEEP 0
22 #if TIMERS
23 #define STARTTICKTIMER(id,str) STARTTIMER(id,str)
24 #define ENDTICKTIMER(id,str) ENDTIMER(id,str)
25 #else
26 #define STARTTICKTIMER(id,str)
27 #define ENDTICKTIMER(id,str)
28 #endif
31 #define MINIMUM_FPS 5
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 {
39 public:
40 TickCallHandler func;
41 EventObject *data;
42 TickCall (TickCallHandler func, EventObject *data)
44 this->func = func;
45 this->data = data;
46 if (this->data)
47 this->data->ref ();
49 virtual ~TickCall ()
51 if (data)
52 data->unref ();
57 class RootClockGroup : public ClockGroup
59 public:
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;
75 protected:
76 virtual ~RootClockGroup () { }
79 TimeManager::TimeManager ()
81 SetObjectType (Type::TIMEMANAGER);
83 if (moonlight_flags & RUNTIME_INIT_MANUAL_TIMESOURCE)
84 source = new ManualTimeSource();
85 else
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;
98 first_tick = true;
99 emitting = 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);
108 g_free (name);
109 root_clock->SetTimeManager (this);
112 TimeManager::~TimeManager ()
114 source->RemoveHandler (TimeSource::TickEvent, source_tick_callback, this);
115 source->unref ();
116 source = NULL;
118 root_clock->Dispose ();
120 timeline->unref ();
121 timeline = NULL;
123 root_clock->unref ();
124 root_clock = NULL;
126 delete applier;
127 applier = NULL;
129 RemoveAllRegisteredTimeouts ();
132 void
133 TimeManager::SetMaximumRefreshRate (int hz)
135 if (hz == 0)
136 hz = 1;
138 max_fps = hz;
139 current_timeout = FPS_TO_DELAY (hz);
140 source->SetTimerFrequency (current_timeout);
141 first_tick = true;
144 void
145 TimeManager::Start()
147 last_global_time = current_global_time = source->GetNow();
148 current_global_time_usec = current_global_time / 10;
149 source->SetTimerFrequency (current_timeout);
150 source->Start ();
151 source_tick_pending = true;
154 void
155 TimeManager::Stop ()
157 source->Stop ();
160 void
161 TimeManager::Shutdown ()
163 RemoveAllRegisteredTimeouts ();
164 source->Stop ();
167 void
168 TimeManager::source_tick_callback (EventObject *sender, EventArgs *calldata, gpointer closure)
170 ((TimeManager *) closure)->SourceTick ();
173 void
174 TimeManager::InvokeTickCalls ()
176 emitting = true;
177 TickCall *call;
178 while ((call = (TickCall *) tick_calls.Pop ())) {
179 call->func (call->data);
180 delete call;
182 dispatcher_calls.Lock ();
183 emitting = false;
184 dispatcher_calls.MoveTo (tick_calls);
185 dispatcher_calls.Unlock ();
188 guint
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));
193 return rv;
196 void
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));
203 void
204 TimeManager::RemoveAllRegisteredTimeouts ()
206 GList *t;
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;
214 void
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);
224 source->Start();
226 #endif
229 struct TickCallFindData {
230 TickCallHandler func;
231 EventObject *data;
234 void
235 TimeManager::RemoveTickCall (TickCallHandler func, EventObject *tick_data)
237 TickCallFindData fd;
239 fd.func = func;
240 fd.data = tick_data;
242 tick_calls.Lock ();
244 List::Node * call = tick_calls.LinkedList ()->Find (find_tick_call, &fd);
245 if (call)
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)
251 source->Stop();
253 #endif
254 tick_calls.Unlock ();
257 void
258 TimeManager::AddDispatcherCall (TickCallHandler func, EventObject *tick_data)
260 dispatcher_calls.Lock ();
261 if (emitting)
262 dispatcher_calls.LinkedList ()->Append (new TickCall (func, tick_data));
263 else
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);
272 source->Start();
274 #endif
278 bool
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);
288 void
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);
296 source->Start();
298 #endif
301 void
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);
309 source->Start();
311 #endif
315 static void
316 spaces (int n)
318 while (n--) putchar (' ');
321 static void
322 output_clock (Clock *clock, int level)
324 spaces (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()) {
338 case Clock::Active:
339 printf ("A");
340 break;
341 case Clock::Filling:
342 printf ("F");
343 break;
344 case Clock::Stopped:
345 printf ("S");
346 break;
349 if (clock->GetIsPaused())
350 printf (" (paused)");
352 printf ("\n");
354 if (clock->Is(Type::CLOCKGROUP)) {
355 ClockGroup *cg = (ClockGroup*)clock;
356 level += 2;
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);
364 void
365 TimeManager::ListClocks()
367 printf ("Currently registered clocks:\n");
368 printf ("============================\n");
370 output_clock (root_clock, 2);
372 printf ("============================\n");
375 void
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());
387 NeedClockTick ();
390 void
391 TimeManager::SourceTick ()
393 TimeManagerOp current_flags = flags;
395 #if PUT_TIME_MANAGER_TO_SLEEP
396 flags = (TimeManagerOp)0;
397 #endif
399 if (current_flags & TIME_MANAGER_TICK_CALL) {
400 STARTTICKTIMER (tm_tick_call, "TimeManager::Tick - Call");
401 InvokeTickCalls ();
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)
413 NeedClockTick ();
415 // ... then cause all clocks to raise the events they've queued up
416 root_clock->RaiseAccumulatedEvents ();
418 applier->Apply ();
419 applier->Flush ();
421 root_clock->RaiseAccumulatedCompleted ();
423 #if CLOCK_DEBUG
424 ListClocks ();
425 #endif
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;