Blame clutter/gdk/clutter-master-clock-gdk.c

Packit 31ecd5
/*
Packit 31ecd5
 * Clutter.
Packit 31ecd5
 *
Packit 31ecd5
 * An OpenGL based 'interactive canvas' library.
Packit 31ecd5
 *
Packit 31ecd5
 * Authored By: Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
Packit 31ecd5
 *
Packit 31ecd5
 * Copyright (C) 2015  Intel Corporation.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is free software; you can redistribute it and/or
Packit 31ecd5
 * modify it under the terms of the GNU Lesser General Public
Packit 31ecd5
 * License as published by the Free Software Foundation; either
Packit 31ecd5
 * version 2 of the License, or (at your option) any later version.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is distributed in the hope that it will be useful,
Packit 31ecd5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 31ecd5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 31ecd5
 * Lesser General Public License for more details.
Packit 31ecd5
 *
Packit 31ecd5
 * You should have received a copy of the GNU Lesser General Public
Packit 31ecd5
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
/*
Packit 31ecd5
 * SECTION:clutter-master-clock-gdk
Packit 31ecd5
 * @short_description: The GDK master clock for all animations
Packit 31ecd5
 *
Packit 31ecd5
 * The #ClutterMasterClockDefault class is the GdkFrameClock based implementation
Packit 31ecd5
 * of #ClutterMasterClock.
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
#ifdef HAVE_CONFIG_H
Packit 31ecd5
#include "config.h"
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
#include <gdk/gdk.h>
Packit 31ecd5
Packit 31ecd5
#include "clutter-master-clock.h"
Packit 31ecd5
#include "clutter-master-clock-gdk.h"
Packit 31ecd5
#include "clutter-stage-gdk.h"
Packit 31ecd5
#include "clutter-debug.h"
Packit 31ecd5
#include "clutter-private.h"
Packit 31ecd5
#include "clutter-stage-manager-private.h"
Packit 31ecd5
#include "clutter-stage-private.h"
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
#define clutter_warn_if_over_budget(master_clock,start_time,section)    G_STMT_START  { \
Packit 31ecd5
  gint64 __delta = g_get_monotonic_time () - start_time;                                \
Packit 31ecd5
  gint64 __budget = master_clock->remaining_budget;                                     \
Packit 31ecd5
  if (__budget > 0 && __delta >= __budget) {                                            \
Packit 31ecd5
    _clutter_diagnostic_message ("%s took %" G_GINT64_FORMAT " microseconds "           \
Packit 31ecd5
                                 "more than the remaining budget of %" G_GINT64_FORMAT  \
Packit 31ecd5
                                 " microseconds",                                       \
Packit 31ecd5
                                 section, __delta - __budget, __budget);                \
Packit 31ecd5
  }                                                                     } G_STMT_END
Packit 31ecd5
#else
Packit 31ecd5
#define clutter_warn_if_over_budget(master_clock,start_time,section)
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
typedef struct _ClutterClockSource              ClutterClockSource;
Packit 31ecd5
Packit 31ecd5
struct _ClutterMasterClockGdk
Packit 31ecd5
{
Packit 31ecd5
  GObject parent_instance;
Packit 31ecd5
Packit 31ecd5
  /* the list of timelines handled by the clock */
Packit 31ecd5
  GSList *timelines;
Packit 31ecd5
Packit 31ecd5
  /* mapping between ClutterStages and GdkFrameClocks.
Packit 31ecd5
   *
Packit 31ecd5
   * @stage_to_clock: a direct mapping because each stage has at most one clock
Packit 31ecd5
   * @clock_to_stage: each clock can have more than one stage
Packit 31ecd5
   */
Packit 31ecd5
  GHashTable *stage_to_clock;
Packit 31ecd5
  GHashTable *clock_to_stage;
Packit 31ecd5
Packit 31ecd5
  /* the current state of the clock, in usecs */
Packit 31ecd5
  gint64 cur_tick;
Packit 31ecd5
Packit 31ecd5
  /* the previous state of the clock, in usecs, used to compute the delta */
Packit 31ecd5
  gint64 prev_tick;
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  gint64 frame_budget;
Packit 31ecd5
  gint64 remaining_budget;
Packit 31ecd5
#endif
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
struct _ClutterClockSource
Packit 31ecd5
{
Packit 31ecd5
  GSource source;
Packit 31ecd5
Packit 31ecd5
  ClutterMasterClock *master_clock;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
static void clutter_master_clock_iface_init (ClutterMasterClockIface *iface);
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE_WITH_CODE (ClutterMasterClockGdk,
Packit 31ecd5
                         clutter_master_clock_gdk,
Packit 31ecd5
                         G_TYPE_OBJECT,
Packit 31ecd5
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MASTER_CLOCK,
Packit 31ecd5
                                                clutter_master_clock_iface_init));
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
master_clock_schedule_forced_stages_updates (ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  GHashTableIter iter;
Packit 31ecd5
  gpointer stage, frame_clock;
Packit 31ecd5
Packit 31ecd5
  g_hash_table_iter_init (&iter, master_clock->stage_to_clock);
Packit 31ecd5
  while (g_hash_table_iter_next (&iter, &stage, &frame_clock))
Packit 31ecd5
    gdk_frame_clock_request_phase (GDK_FRAME_CLOCK (frame_clock),
Packit 31ecd5
                                   GDK_FRAME_CLOCK_PHASE_PAINT);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
master_clock_sync_frame_clock_update (ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  gboolean updating = master_clock->timelines != NULL;
Packit 31ecd5
  gpointer frame_clock, stage_list;
Packit 31ecd5
  GHashTableIter iter;
Packit 31ecd5
Packit 31ecd5
  g_hash_table_iter_init (&iter, master_clock->clock_to_stage);
Packit 31ecd5
  while (g_hash_table_iter_next (&iter, &frame_clock, &stage_list))
Packit 31ecd5
    {
Packit 31ecd5
      gboolean clock_updating =
Packit 31ecd5
        GPOINTER_TO_UINT (g_object_get_data (frame_clock,
Packit 31ecd5
                                             "clutter-master-clock-updating"));
Packit 31ecd5
      if (clock_updating != updating)
Packit 31ecd5
        {
Packit 31ecd5
          if (updating)
Packit 31ecd5
            gdk_frame_clock_begin_updating (GDK_FRAME_CLOCK (frame_clock));
Packit 31ecd5
          else
Packit 31ecd5
            gdk_frame_clock_end_updating (GDK_FRAME_CLOCK (frame_clock));
Packit 31ecd5
          g_object_set_data (frame_clock,
Packit 31ecd5
                             "clutter-master-clock-updating",
Packit 31ecd5
                             GUINT_TO_POINTER (updating));
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
master_clock_schedule_stage_update (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                                    ClutterStage          *stage,
Packit 31ecd5
                                    GdkFrameClock         *frame_clock)
Packit 31ecd5
{
Packit 31ecd5
  /* Clear the old update time */
Packit 31ecd5
  _clutter_stage_clear_update_time (stage);
Packit 31ecd5
Packit 31ecd5
  /* And if there is still work to be done, schedule a new one */
Packit 31ecd5
  if (_clutter_stage_has_queued_events (stage) ||
Packit 31ecd5
      _clutter_stage_needs_update (stage))
Packit 31ecd5
    _clutter_stage_schedule_update (stage);
Packit 31ecd5
Packit 31ecd5
  /* We can avoid to schedule a new frame if the stage doesn't need
Packit 31ecd5
   * anymore redrawing. But in the case we still have timelines alive,
Packit 31ecd5
   * we have no choice, we need to advance the timelines for the next
Packit 31ecd5
   * frame. */
Packit 31ecd5
  if (master_clock->timelines != NULL)
Packit 31ecd5
    gdk_frame_clock_request_phase (frame_clock, GDK_FRAME_CLOCK_PHASE_PAINT);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
master_clock_process_stage_events (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                                   ClutterStage          *stage)
Packit 31ecd5
{
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  gint64 start = g_get_monotonic_time ();
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  /* Process queued events */
Packit 31ecd5
  _clutter_stage_process_queued_events (stage);
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  if (_clutter_diagnostic_enabled ())
Packit 31ecd5
    clutter_warn_if_over_budget (master_clock, start, "Event processing");
Packit 31ecd5
Packit 31ecd5
  master_clock->remaining_budget -= (g_get_monotonic_time () - start);
Packit 31ecd5
#endif
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/*
Packit 31ecd5
 * master_clock_advance_timelines:
Packit 31ecd5
 * @master_clock: a #ClutterMasterClock
Packit 31ecd5
 *
Packit 31ecd5
 * Advances all the timelines held by the master clock. This function
Packit 31ecd5
 * should be called before calling _clutter_stage_do_update() to
Packit 31ecd5
 * make sure that all the timelines are advanced and the scene is updated.
Packit 31ecd5
 */
Packit 31ecd5
static void
Packit 31ecd5
master_clock_advance_timelines (ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  GSList *timelines, *l;
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  gint64 start = g_get_monotonic_time ();
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  /* we protect ourselves from timelines being removed during
Packit 31ecd5
   * the advancement by other timelines by copying the list of
Packit 31ecd5
   * timelines, taking a reference on them, iterating over the
Packit 31ecd5
   * copied list and then releasing the reference.
Packit 31ecd5
   *
Packit 31ecd5
   * we cannot simply take a reference on the timelines and still
Packit 31ecd5
   * use the list held by the master clock because the do_tick()
Packit 31ecd5
   * might result in the creation of a new timeline, which gets
Packit 31ecd5
   * added at the end of the list with no reference increase and
Packit 31ecd5
   * thus gets disposed at the end of the iteration.
Packit 31ecd5
   *
Packit 31ecd5
   * this implies that a newly added timeline will not be advanced
Packit 31ecd5
   * by this clock iteration, which is perfectly fine since we're
Packit 31ecd5
   * in its first cycle.
Packit 31ecd5
   *
Packit 31ecd5
   * we also cannot steal the master clock timelines list because
Packit 31ecd5
   * a timeline might be removed as the direct result of do_tick()
Packit 31ecd5
   * and remove_timeline() would not find the timeline, failing
Packit 31ecd5
   * and leaving a dangling pointer behind.
Packit 31ecd5
   */
Packit 31ecd5
  timelines = g_slist_copy (master_clock->timelines);
Packit 31ecd5
  g_slist_foreach (timelines, (GFunc) g_object_ref, NULL);
Packit 31ecd5
Packit 31ecd5
  for (l = timelines; l != NULL; l = l->next)
Packit 31ecd5
    _clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000);
Packit 31ecd5
Packit 31ecd5
  g_slist_foreach (timelines, (GFunc) g_object_unref, NULL);
Packit 31ecd5
  g_slist_free (timelines);
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  if (_clutter_diagnostic_enabled ())
Packit 31ecd5
    clutter_warn_if_over_budget (master_clock, start, "Animations");
Packit 31ecd5
Packit 31ecd5
  master_clock->remaining_budget -= (g_get_monotonic_time () - start);
Packit 31ecd5
#endif
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
master_clock_update_stage (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                           ClutterStage          *stage)
Packit 31ecd5
{
Packit 31ecd5
  gboolean stage_updated = FALSE;
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  gint64 start = g_get_monotonic_time ();
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
Packit 31ecd5
Packit 31ecd5
  /* Update any stage that needs redraw/relayout after the clock
Packit 31ecd5
   * is advanced.
Packit 31ecd5
   */
Packit 31ecd5
  stage_updated |= _clutter_stage_do_update (stage);
Packit 31ecd5
Packit 31ecd5
  _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  if (_clutter_diagnostic_enabled ())
Packit 31ecd5
    clutter_warn_if_over_budget (master_clock, start, "Updating the stage");
Packit 31ecd5
Packit 31ecd5
  master_clock->remaining_budget -= (g_get_monotonic_time () - start);
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  return stage_updated;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_update (GdkFrameClock         *frame_clock,
Packit 31ecd5
                                 ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  GList *stages, *l;
Packit 31ecd5
Packit 31ecd5
  _clutter_threads_acquire_lock ();
Packit 31ecd5
Packit 31ecd5
  /* Get the time to use for this frame */
Packit 31ecd5
  master_clock->cur_tick = gdk_frame_clock_get_frame_time (frame_clock);
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  /* Update the remaining budget */
Packit 31ecd5
  master_clock->remaining_budget = master_clock->frame_budget;
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  stages = g_hash_table_lookup (master_clock->clock_to_stage, frame_clock);
Packit 31ecd5
  CLUTTER_NOTE (SCHEDULER, "Updating %d stages tied to frame clock %p",
Packit 31ecd5
                g_list_length (stages), frame_clock);
Packit 31ecd5
  for (l = stages; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      ClutterStage *stage = l->data;
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCHEDULER, "Master clock (stage:%p, clock:%p) [tick]", stage, frame_clock);
Packit 31ecd5
Packit 31ecd5
      /* Each frame is split into three separate phases: */
Packit 31ecd5
Packit 31ecd5
      /* 1. process all the events; goes through the stage's event queue
Packit 31ecd5
       *    and processes each event according to its type, then emits the
Packit 31ecd5
       *    various signals that are associated with the event
Packit 31ecd5
       */
Packit 31ecd5
      master_clock_process_stage_events (master_clock, stage);
Packit 31ecd5
Packit 31ecd5
      /* 2. advance the timelines */
Packit 31ecd5
      master_clock_advance_timelines (master_clock);
Packit 31ecd5
Packit 31ecd5
      /* 3. relayout and redraw the stage; the stage might have been
Packit 31ecd5
       *    destroyed in 1. when processing events, check whether it's
Packit 31ecd5
       *    still alive.
Packit 31ecd5
       */
Packit 31ecd5
Packit 31ecd5
      if (g_hash_table_lookup (master_clock->stage_to_clock, stage) != NULL)
Packit 31ecd5
        {
Packit 31ecd5
          master_clock_update_stage (master_clock, stage);
Packit 31ecd5
          master_clock_schedule_stage_update (master_clock, stage, frame_clock);
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  master_clock->prev_tick = master_clock->cur_tick;
Packit 31ecd5
Packit 31ecd5
  _clutter_threads_release_lock ();
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_remove_stage_clock (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                                             ClutterStage          *stage)
Packit 31ecd5
{
Packit 31ecd5
  gpointer frame_clock = g_hash_table_lookup (master_clock->stage_to_clock, stage);
Packit 31ecd5
  GList *stages;
Packit 31ecd5
Packit 31ecd5
  if (frame_clock == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCHEDULER, "Removing stage %p with clock %p", stage, frame_clock);
Packit 31ecd5
Packit 31ecd5
  g_hash_table_remove (master_clock->stage_to_clock, stage);
Packit 31ecd5
Packit 31ecd5
  stages = g_hash_table_lookup (master_clock->clock_to_stage, frame_clock);
Packit 31ecd5
  if (stages != NULL)
Packit 31ecd5
    {
Packit 31ecd5
      if (stages->next == NULL)
Packit 31ecd5
        {
Packit 31ecd5
          /* Deleting the last stage linked to a given clock. We can stop
Packit 31ecd5
             listening to that clock and also tell the clock we're finish
Packit 31ecd5
             updating it. */
Packit 31ecd5
          if (GPOINTER_TO_UINT (g_object_get_data (frame_clock,
Packit 31ecd5
                                                   "clutter-master-clock-updating")))
Packit 31ecd5
            {
Packit 31ecd5
              gdk_frame_clock_end_updating (GDK_FRAME_CLOCK (frame_clock));
Packit 31ecd5
              g_object_set_data (frame_clock, "clutter-master-clock-updating", NULL);
Packit 31ecd5
            }
Packit 31ecd5
          g_signal_handlers_disconnect_by_func (frame_clock,
Packit 31ecd5
                                                clutter_master_clock_gdk_update,
Packit 31ecd5
                                                master_clock);
Packit 31ecd5
Packit 31ecd5
          g_hash_table_remove (master_clock->clock_to_stage, frame_clock);
Packit 31ecd5
          g_list_free (stages);
Packit 31ecd5
        }
Packit 31ecd5
      else
Packit 31ecd5
        {
Packit 31ecd5
          stages = g_list_remove (stages, stage);
Packit 31ecd5
          g_hash_table_replace (master_clock->clock_to_stage,
Packit 31ecd5
                                g_object_ref (frame_clock),
Packit 31ecd5
                                stages);
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_add_stage_clock (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                                          ClutterStage          *stage,
Packit 31ecd5
                                          GdkFrameClock         *frame_clock)
Packit 31ecd5
{
Packit 31ecd5
  GList *stages;
Packit 31ecd5
Packit 31ecd5
  clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCHEDULER, "Adding stage %p with clock %p", stage, frame_clock);
Packit 31ecd5
Packit 31ecd5
  g_hash_table_insert (master_clock->stage_to_clock, stage, g_object_ref (frame_clock));
Packit 31ecd5
Packit 31ecd5
  stages = g_hash_table_lookup (master_clock->clock_to_stage, frame_clock);
Packit 31ecd5
  if (stages == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      g_hash_table_insert (master_clock->clock_to_stage, g_object_ref (frame_clock),
Packit 31ecd5
                           g_list_append (NULL, stage));
Packit 31ecd5
Packit 31ecd5
      g_signal_connect (frame_clock, "paint",
Packit 31ecd5
                        G_CALLBACK (clutter_master_clock_gdk_update),
Packit 31ecd5
                        master_clock);
Packit 31ecd5
    }
Packit 31ecd5
  else
Packit 31ecd5
    stages = g_list_append (stages, stage);
Packit 31ecd5
Packit 31ecd5
  if (master_clock->timelines != NULL)
Packit 31ecd5
    {
Packit 31ecd5
      _clutter_master_clock_start_running ((ClutterMasterClock *) master_clock);
Packit 31ecd5
      /* We only need to synchronize the frame clock state if we have
Packit 31ecd5
         timelines running. */
Packit 31ecd5
      master_clock_sync_frame_clock_update (master_clock);
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_listen_to_stage (ClutterMasterClockGdk *master_clock,
Packit 31ecd5
                                          ClutterStage          *stage)
Packit 31ecd5
{
Packit 31ecd5
  ClutterStageWindow *stage_window;
Packit 31ecd5
  ClutterStageGdk *stage_window_gdk;
Packit 31ecd5
  GdkFrameClock *frame_clock;
Packit 31ecd5
Packit 31ecd5
  stage_window = _clutter_stage_get_window (stage);
Packit 31ecd5
  if (stage_window == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
      return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  stage_window_gdk = CLUTTER_STAGE_GDK (stage_window);
Packit 31ecd5
  if (stage_window_gdk->window == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
      return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  frame_clock = gdk_window_get_frame_clock (stage_window_gdk->window);
Packit 31ecd5
  if (frame_clock == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
      return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  clutter_master_clock_gdk_add_stage_clock (master_clock, stage, frame_clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_stage_visibility (ClutterStage          *stage,
Packit 31ecd5
                                           GParamSpec            *spec,
Packit 31ecd5
                                           ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  ClutterActor *actor = CLUTTER_ACTOR (stage);
Packit 31ecd5
  if (clutter_actor_is_mapped (actor))
Packit 31ecd5
    clutter_master_clock_gdk_listen_to_stage (master_clock, stage);
Packit 31ecd5
  else
Packit 31ecd5
    clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_stage_added (ClutterStageManager   *manager,
Packit 31ecd5
                                      ClutterStage          *stage,
Packit 31ecd5
                                      ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  g_signal_connect (stage, "notify::mapped",
Packit 31ecd5
                    G_CALLBACK (clutter_master_clock_gdk_stage_visibility),
Packit 31ecd5
                    master_clock);
Packit 31ecd5
Packit 31ecd5
  clutter_master_clock_gdk_stage_visibility (stage, NULL, master_clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_stage_removed (ClutterStageManager   *manager,
Packit 31ecd5
                                        ClutterStage          *stage,
Packit 31ecd5
                                        ClutterMasterClockGdk *master_clock)
Packit 31ecd5
{
Packit 31ecd5
  clutter_master_clock_gdk_remove_stage_clock (master_clock, stage);
Packit 31ecd5
Packit 31ecd5
  g_signal_handlers_disconnect_by_func (stage,
Packit 31ecd5
                                        clutter_master_clock_gdk_stage_visibility,
Packit 31ecd5
                                        master_clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_dispose (GObject *gobject)
Packit 31ecd5
{
Packit 31ecd5
  ClutterStageManager *manager = clutter_stage_manager_get_default ();
Packit 31ecd5
Packit 31ecd5
  g_signal_handlers_disconnect_by_func (manager,
Packit 31ecd5
                                        clutter_master_clock_gdk_stage_added,
Packit 31ecd5
                                        gobject);
Packit 31ecd5
  g_signal_handlers_disconnect_by_func (manager,
Packit 31ecd5
                                        clutter_master_clock_gdk_stage_removed,
Packit 31ecd5
                                        gobject);
Packit 31ecd5
Packit 31ecd5
  G_OBJECT_CLASS (clutter_master_clock_gdk_parent_class)->dispose (gobject);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_finalize (GObject *gobject)
Packit 31ecd5
{
Packit 31ecd5
  ClutterMasterClockGdk *master_clock = CLUTTER_MASTER_CLOCK_GDK (gobject);
Packit 31ecd5
Packit 31ecd5
  g_hash_table_unref (master_clock->clock_to_stage);
Packit 31ecd5
  g_hash_table_unref (master_clock->stage_to_clock);
Packit 31ecd5
  g_slist_free (master_clock->timelines);
Packit 31ecd5
Packit 31ecd5
  G_OBJECT_CLASS (clutter_master_clock_gdk_parent_class)->finalize (gobject);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_class_init (ClutterMasterClockGdkClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 31ecd5
Packit 31ecd5
  gobject_class->dispose = clutter_master_clock_gdk_dispose;
Packit 31ecd5
  gobject_class->finalize = clutter_master_clock_gdk_finalize;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_init (ClutterMasterClockGdk *self)
Packit 31ecd5
{
Packit 31ecd5
  ClutterStageManager *manager;
Packit 31ecd5
  const GSList *stages, *l;
Packit 31ecd5
Packit 31ecd5
#ifdef CLUTTER_ENABLE_DEBUG
Packit 31ecd5
  self->frame_budget = G_USEC_PER_SEC / 60;
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
  self->clock_to_stage = g_hash_table_new_full (g_direct_hash, g_direct_equal,
Packit 31ecd5
                                                g_object_unref, NULL);
Packit 31ecd5
  self->stage_to_clock = g_hash_table_new_full (g_direct_hash, g_direct_equal,
Packit 31ecd5
                                                NULL, g_object_unref);
Packit 31ecd5
Packit 31ecd5
  manager = clutter_stage_manager_get_default ();
Packit 31ecd5
  g_signal_connect (manager, "stage-added",
Packit 31ecd5
                    G_CALLBACK (clutter_master_clock_gdk_stage_added), self);
Packit 31ecd5
  g_signal_connect (manager, "stage-removed",
Packit 31ecd5
                    G_CALLBACK (clutter_master_clock_gdk_stage_removed), self);
Packit 31ecd5
Packit 31ecd5
  stages = clutter_stage_manager_peek_stages (manager);
Packit 31ecd5
  for (l = stages; l; l = l->next)
Packit 31ecd5
    clutter_master_clock_gdk_stage_added (manager, l->data, self);
Packit 31ecd5
Packit 31ecd5
  if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_CONTINUOUS_REDRAW))
Packit 31ecd5
    g_warning ("Continuous redraw is not supported with the GDK backend.");
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_add_timeline (ClutterMasterClock *clock,
Packit 31ecd5
                                       ClutterTimeline    *timeline)
Packit 31ecd5
{
Packit 31ecd5
  ClutterMasterClockGdk *master_clock = (ClutterMasterClockGdk *) clock;
Packit 31ecd5
  gboolean is_first;
Packit 31ecd5
Packit 31ecd5
  if (g_slist_find (master_clock->timelines, timeline))
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  is_first = master_clock->timelines == NULL;
Packit 31ecd5
Packit 31ecd5
  master_clock->timelines = g_slist_prepend (master_clock->timelines,
Packit 31ecd5
                                             timeline);
Packit 31ecd5
Packit 31ecd5
  if (is_first)
Packit 31ecd5
    {
Packit 31ecd5
      _clutter_master_clock_start_running (clock);
Packit 31ecd5
      /* Sync frame clock update state if needed. */
Packit 31ecd5
      master_clock_sync_frame_clock_update (master_clock);
Packit 31ecd5
    }
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_remove_timeline (ClutterMasterClock *clock,
Packit 31ecd5
                                          ClutterTimeline    *timeline)
Packit 31ecd5
{
Packit 31ecd5
  ClutterMasterClockGdk *master_clock = (ClutterMasterClockGdk *) clock;
Packit 31ecd5
Packit 31ecd5
  master_clock->timelines = g_slist_remove (master_clock->timelines,
Packit 31ecd5
                                            timeline);
Packit 31ecd5
Packit 31ecd5
  /* Sync frame clock update state if we have no more timelines running. */
Packit 31ecd5
  if (master_clock->timelines == NULL)
Packit 31ecd5
    master_clock_sync_frame_clock_update (master_clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_start_running (ClutterMasterClock *clock)
Packit 31ecd5
{
Packit 31ecd5
  master_clock_schedule_forced_stages_updates ((ClutterMasterClockGdk *) clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_ensure_next_iteration (ClutterMasterClock *clock)
Packit 31ecd5
{
Packit 31ecd5
  master_clock_schedule_forced_stages_updates ((ClutterMasterClockGdk *) clock);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_gdk_set_paused (ClutterMasterClock *clock,
Packit 31ecd5
                                     gboolean            paused)
Packit 31ecd5
{
Packit 31ecd5
  /* GdkFrameClock runs the show here. We do not decide whether the
Packit 31ecd5
     clock is paused or not. */
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_master_clock_iface_init (ClutterMasterClockIface *iface)
Packit 31ecd5
{
Packit 31ecd5
  iface->add_timeline = clutter_master_clock_gdk_add_timeline;
Packit 31ecd5
  iface->remove_timeline = clutter_master_clock_gdk_remove_timeline;
Packit 31ecd5
  iface->start_running = clutter_master_clock_gdk_start_running;
Packit 31ecd5
  iface->ensure_next_iteration = clutter_master_clock_gdk_ensure_next_iteration;
Packit 31ecd5
  iface->set_paused = clutter_master_clock_gdk_set_paused;
Packit 31ecd5
}