static void master_clock_process_events (ClutterMasterClockDefault *master_clock, GSList *stages) { GSList *l; #ifdef CLUTTER_ENABLE_DEBUG gint64 start = g_get_monotonic_time (); #endif /* Process queued events */ for (l = stages; l != NULL; l = l->next) _clutter_stage_process_queued_events (l->data); #ifdef CLUTTER_ENABLE_DEBUG if (_clutter_diagnostic_enabled ()) clutter_warn_if_over_budget (master_clock, start, "Event processing"); master_clock->remaining_budget -= (g_get_monotonic_time () - start); #endif }
static gboolean clutter_clock_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClock *master_clock = clock_source->master_clock; ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); gboolean stages_updated = FALSE; GSList *stages, *l; CLUTTER_STATIC_TIMER (master_dispatch_timer, "Mainloop", "Master Clock", "Master clock dispatch", 0); CLUTTER_STATIC_TIMER (master_event_process, "Master Clock", "Event Processing", "The time spent processing events on all stages", 0); CLUTTER_TIMER_START (_clutter_uprof_context, master_dispatch_timer); CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); clutter_threads_enter (); /* Get the time to use for this frame */ #if GLIB_CHECK_VERSION (2, 27, 3) master_clock->cur_tick = g_source_get_time (source); #else { GTimeVal source_time; g_source_get_current_time (source, &source_time); master_clock->cur_tick = source_time.tv_sec * 1000000L + source_time.tv_usec; } #endif /* We need to protect ourselves against stages being destroyed during * event handling */ stages = clutter_stage_manager_list_stages (stage_manager); g_slist_foreach (stages, (GFunc) g_object_ref, NULL); CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process); master_clock->idle = FALSE; /* Process queued events */ for (l = stages; l != NULL; l = l->next) { /* NB: If a stage is busy waiting for a swap-buffers completion then * we don't process its events so we can maximize the benefits of * motion compression, and avoid multiple picks per frame. */ if (_clutter_stage_get_pending_swaps (l->data) == 0) _clutter_stage_process_queued_events (l->data); } CLUTTER_TIMER_STOP (_clutter_uprof_context, master_event_process); _clutter_master_clock_advance (master_clock); _clutter_run_repaint_functions (); /* Update any stage that needs redraw/relayout after the clock * is advanced. */ for (l = stages; l != NULL; l = l->next) { /* If a stage has a swap-buffers pending we don't want to draw to it * in case the driver may block the CPU while it waits for the next * backbuffer to become available. * * TODO: We should be able to identify if we are running triple or N * buffered and in these cases we can still draw if there is 1 swap * pending so we can hopefully always be ready to swap for the next * vblank and really match the vsync frequency. */ if (_clutter_stage_get_pending_swaps (l->data) == 0) stages_updated |= _clutter_stage_do_update (l->data); } /* The master clock goes idle if no stages were updated and falls back * to polling for timeline progressions... */ if (!stages_updated) master_clock->idle = TRUE; g_slist_foreach (stages, (GFunc) g_object_unref, NULL); g_slist_free (stages); master_clock->prev_tick = master_clock->cur_tick; clutter_threads_leave (); CLUTTER_TIMER_STOP (_clutter_uprof_context, master_dispatch_timer); return TRUE; }