add the 2.1-bootstrap dir to MONO_PATH when running smcs
[moon.git] / src / timemanager.cpp
blobe09f5372ecf44412f162b0f66d06f7c07084d2f4
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 TIMERS 0
21 #define PUT_TIME_MANAGER_TO_SLEEP 0
23 #if TIMERS
24 #define STARTTICKTIMER(id,str) STARTTIMER(id,str)
25 #define ENDTICKTIMER(id,str) ENDTIMER(it,str)
26 #else
27 #define STARTTICKTIMER(id,str)
28 #define ENDTICKTIMER(id,str)
29 #endif
32 #define MINIMUM_FPS 5
33 #define DEFAULT_FPS 50
34 #define MAXIMUM_FPS 50
36 #define FPS_TO_DELAY(fps) (int)(((double)1/(fps)) * 1000)
37 #define DELAY_TO_FPS(delay) (1000.0 / delay)
39 class TickCall : public List::Node {
40 public:
41 TickCallHandler func;
42 EventObject *data;
43 TickCall (TickCallHandler func, EventObject *data)
45 this->func = func;
46 this->data = data;
47 if (this->data)
48 this->data->ref ();
50 virtual ~TickCall ()
52 if (data)
53 data->unref ();
58 class RootClockGroup : public ClockGroup
60 public:
61 RootClockGroup (TimelineGroup *timeline) : ClockGroup (timeline, true) { }
63 virtual bool UpdateFromParentTime (TimeSpan parentTime)
65 bool rv = Clock::UpdateFromParentTime (parentTime);
67 bool children_rv = false;
68 for (GList *l = child_clocks; l; l = l->next) {
69 Clock *clock = (Clock*)l->data;
70 children_rv = clock->UpdateFromParentTime (current_time) || children_rv;
73 return rv && children_rv;
76 protected:
77 virtual ~RootClockGroup () { }
80 TimeManager::TimeManager ()
82 SetObjectType (Type::TIMEMANAGER);
84 if (moonlight_flags & RUNTIME_INIT_MANUAL_TIMESOURCE)
85 source = new ManualTimeSource();
86 else
87 source = new SystemTimeSource(Deployment::GetCurrent ());
89 current_timeout = FPS_TO_DELAY (DEFAULT_FPS); /* something suitably small */
90 max_fps = MAXIMUM_FPS;
91 flags = (TimeManagerOp) (TIME_MANAGER_UPDATE_CLOCKS | TIME_MANAGER_RENDER | TIME_MANAGER_TICK_CALL /*| TIME_MANAGER_UPDATE_INPUT*/);
93 start_time = source->GetNow ();
94 start_time_usec = start_time / 10;
95 source->AddHandler (TimeSource::TickEvent, source_tick_callback, this);
97 registered_timeouts = NULL;
98 source_tick_pending = false;
99 first_tick = true;
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 timeline->unref ();
119 timeline = NULL;
121 root_clock->unref ();
122 root_clock = NULL;
124 delete applier;
126 RemoveAllRegisteredTimeouts ();
129 void
130 TimeManager::SetMaximumRefreshRate (int hz)
132 if (hz == 0)
133 hz = 1;
135 max_fps = hz;
136 current_timeout = FPS_TO_DELAY (hz);
137 source->SetTimerFrequency (current_timeout);
138 first_tick = true;
141 void
142 TimeManager::Start()
144 last_global_time = current_global_time = source->GetNow();
145 current_global_time_usec = current_global_time / 10;
146 source->SetTimerFrequency (current_timeout);
147 source->Start ();
148 source_tick_pending = true;
151 void
152 TimeManager::Stop ()
154 source->Stop ();
157 void
158 TimeManager::Shutdown ()
160 RemoveAllRegisteredTimeouts ();
161 source->Stop ();
164 void
165 TimeManager::source_tick_callback (EventObject *sender, EventArgs *calldata, gpointer closure)
167 ((TimeManager *) closure)->SourceTick ();
170 bool
171 TimeManager::InvokeTickCall ()
173 TickCall *call = (TickCall *) tick_calls.Pop ();
175 if (call == NULL)
176 return false;
178 call->func (call->data);
179 delete call;
181 return true;
184 void
185 TimeManager::InvokeTickCalls ()
187 bool remaining_tick_calls = false;
188 do {
189 remaining_tick_calls = InvokeTickCall ();
190 } while (remaining_tick_calls);
193 guint
194 TimeManager::AddTimeout (gint priority, guint ms_interval, GSourceFunc func, gpointer tick_data)
196 guint rv = g_timeout_add_full (priority, ms_interval, func, tick_data, NULL);
197 registered_timeouts = g_list_prepend (registered_timeouts, GUINT_TO_POINTER (rv));
198 return rv;
201 void
202 TimeManager::RemoveTimeout (guint timeout_id)
204 g_source_remove (timeout_id);
205 registered_timeouts = g_list_remove_all (registered_timeouts, GUINT_TO_POINTER (timeout_id));
208 void
209 TimeManager::RemoveAllRegisteredTimeouts ()
211 GList *t;
212 for (t = registered_timeouts; t; t = t->next)
213 g_source_remove (GPOINTER_TO_UINT (t->data));
215 g_list_free (registered_timeouts);
216 registered_timeouts = NULL;
219 void
220 TimeManager::AddTickCall (TickCallHandler func, EventObject *tick_data)
222 tick_calls.Push (new TickCall (func, tick_data));
224 #if PUT_TIME_MANAGER_TO_SLEEP
225 flags = (TimeManagerOp)(flags | TIME_MANAGER_TICK_CALL);
226 if (!source_tick_pending) {
227 source_tick_pending = true;
228 source->SetTimerFrequency (current_timeout);
229 source->Start();
231 #endif
234 struct TickCallFindData {
235 TickCallHandler func;
236 EventObject *data;
239 void
240 TimeManager::RemoveTickCall (TickCallHandler func, EventObject *tick_data)
242 TickCallFindData fd;
244 fd.func = func;
245 fd.data = tick_data;
247 tick_calls.Lock ();
249 List::Node * call = tick_calls.LinkedList ()->Find (find_tick_call, &fd);
250 if (call)
251 tick_calls.LinkedList ()->Remove (call);
252 #if PUT_TIME_MANAGER_TO_SLEEP
253 if (tick_calls.IsEmpty()) {
254 flags = (TimeManagerOp)(flags & ~TIME_MANAGER_TICK_CALL);
255 if (flags == 0 && source_tick_pending)
256 source->Stop();
258 #endif
259 tick_calls.Unlock ();
262 bool
263 find_tick_call (List::Node *node, void *data)
265 TickCall *tc = (TickCall*)node;
266 TickCallFindData *fd = (TickCallFindData*)data;
268 return (tc->func == fd->func &&
269 tc->data == fd->data);
272 void
273 TimeManager::NeedRedraw ()
275 #if PUT_TIME_MANAGER_TO_SLEEP
276 flags = (TimeManagerOp)(flags | TIME_MANAGER_RENDER);
277 if (!source_tick_pending) {
278 source_tick_pending = true;
279 source->SetTimerFrequency (current_timeout);
280 source->Start();
282 #endif
285 void
286 TimeManager::NeedClockTick ()
288 #if PUT_TIME_MANAGER_TO_SLEEP
289 flags = (TimeManagerOp)(flags | TIME_MANAGER_UPDATE_CLOCKS);
290 if (!source_tick_pending) {
291 source_tick_pending = true;
292 source->SetTimerFrequency (current_timeout);
293 source->Start();
295 #endif
299 static void
300 spaces (int n)
302 while (n--) putchar (' ');
306 static void
307 output_clock (Clock *clock, int level)
309 spaces (level);
310 printf (clock->Is(Type::CLOCKGROUP) ? "ClockGroup " : "Clock ");
311 printf ("(%p) ", clock);
312 if (clock->GetName ()) {
313 printf ("'%s' ", clock->GetName());
316 // getting the natural duration here upsets the clock, so let's not
317 // printf ("%lld / %lld (%.2f) ", clock->GetCurrentTime(), clock->GetNaturalDuration().GetTimeSpan(), clock->GetCurrentProgress());
318 printf ("%lld (%.2f) ", clock->GetCurrentTime(), clock->GetCurrentProgress());
320 printf ("%lld ", clock->GetTimeline()->GetBeginTime());
322 switch (clock->GetClockState()) {
323 case Clock::Active:
324 printf ("A");
325 break;
326 case Clock::Filling:
327 printf ("F");
328 break;
329 case Clock::Stopped:
330 printf ("S");
331 break;
334 if (clock->GetIsPaused())
335 printf (" (paused)");
337 printf ("\n");
339 if (clock->Is(Type::CLOCKGROUP)) {
340 ClockGroup *cg = (ClockGroup*)clock;
341 level += 2;
342 for (GList *l = cg->child_clocks; l; l = l->next) {
343 // if (((Clock*)l->data)->GetClockState () != Clock::Stopped)
344 output_clock ((Clock*)l->data, level);
349 void
350 TimeManager::ListClocks()
352 printf ("Currently registered clocks:\n");
353 printf ("============================\n");
355 output_clock (root_clock, 2);
357 printf ("============================\n");
360 void
361 TimeManager::AddClock (Clock *clock)
363 root_clock->AddChild (clock);
365 // we delay starting the surface's ClockGroup until the first
366 // child has been added. otherwise we run into timing issues
367 // between timelines that explicitly set a BeginTime and those
368 // that don't (and so default to 00:00:00).
369 if (root_clock->GetClockState() != Clock::Active)
370 root_clock->Begin (GetCurrentTime());
372 NeedClockTick ();
375 void
376 TimeManager::SourceTick ()
378 TimeManagerOp current_flags = flags;
380 #if PUT_TIME_MANAGER_TO_SLEEP
381 flags = (TimeManagerOp)0;
382 #endif
384 if (current_flags & TIME_MANAGER_TICK_CALL) {
385 InvokeTickCalls ();
388 if (current_flags & TIME_MANAGER_UPDATE_CLOCKS) {
389 STARTTICKTIMER (tick_update_clocks, "TimeManager::Tick - UpdateClocks");
390 current_global_time = source->GetNow();
391 current_global_time_usec = current_global_time / 10;
393 bool need_another_tick = root_clock->UpdateFromParentTime (GetCurrentTime());
395 if (need_another_tick)
396 NeedClockTick ();
398 // ... then cause all clocks to raise the events they've queued up
399 root_clock->RaiseAccumulatedEvents ();
401 applier->Apply ();
402 applier->Flush ();
404 root_clock->RaiseAccumulatedCompleted ();
406 #if CLOCK_DEBUG
407 ListClocks ();
408 #endif
410 ENDTICKTIMER (tick_update_clocks, "TimeManager::Tick - UpdateClocks");
413 if (current_flags & TIME_MANAGER_UPDATE_INPUT) {
414 STARTTICKTIMER (tick_input, "TimeManager::Tick - Input");
415 Emit (UpdateInputEvent);
416 ENDTICKTIMER (tick_input, "TimeManager::Tick - Input");
419 if (current_flags & TIME_MANAGER_RENDER) {
420 // fprintf (stderr, "rendering\n"); fflush (stderr);
421 STARTTICKTIMER (tick_render, "TimeManager::Tick - Render");
422 Emit (RenderEvent, new RenderingEventArgs (get_now()));
423 ENDTICKTIMER (tick_render, "TimeManager::Tick - Render");
426 last_global_time = current_global_time;