static void
deceleration_new_frame_cb (ClutterTimeline *timeline,
    gint frame_num,
    ChamplainKineticScrollView *scroll)
{
  ChamplainKineticScrollViewPrivate *priv = scroll->priv;

  if (priv->viewport)
    {
      gdouble value, lower, upper;
      ChamplainAdjustment *hadjust, *vadjust;
      gint i;
      gboolean stop = TRUE;

      champlain_viewport_get_adjustments (CHAMPLAIN_VIEWPORT (priv->viewport),
          &hadjust,
          &vadjust);

      for (i = 0; i < clutter_timeline_get_delta (timeline) / 15; i++)
        {
          champlain_adjustment_set_value (hadjust,
              priv->dx +
              champlain_adjustment_get_value (hadjust));
          champlain_adjustment_set_value (vadjust,
              priv->dy +
              champlain_adjustment_get_value (vadjust));
          priv->dx = (priv->dx / priv->decel_rate);
          priv->dy = (priv->dy / priv->decel_rate);
        }

      /* Check if we've hit the upper or lower bounds and stop the timeline */
      champlain_adjustment_get_values (hadjust, &value, &lower, &upper,
          NULL);
      if (((priv->dx > 0) && (value < upper)) ||
          ((priv->dx < 0) && (value > lower)))
        stop = FALSE;

      if (stop)
        {
          champlain_adjustment_get_values (vadjust, &value, &lower, &upper,
              NULL);
          if (((priv->dy > 0) && (value < upper)) ||
              ((priv->dy < 0) && (value > lower)))
            stop = FALSE;
        }

      if (stop)
        {
          clutter_timeline_stop (timeline);
          deceleration_completed_cb (timeline, scroll);
        }
    }
}
// handleNewFrame is the function that is called ever 120 milliseconds via the timeline!
// This is where ALL animation updates will happen.
void Animation::handleNewFrame(ClutterTimeline *timeline, gint frame_num, gpointer user_data) {

    // Rebuild the struct from the pointer we handed in:
    AnimationData *data;
    data = (AnimationData *) user_data;
    TCLControl *tcl = data->tcl; // tcl is STILL a pointer to the main TCLControl object
    Animation *animation = data->animationObject;

    // Error object for GDK/Clutter calls that need them
    error = NULL;

    shaderAnimation(tcl);

    // Send the updated color buffer to the strands
    if (tcl->enabled) {
        tcl->Update();
    }

    // Dump the colors from the color buffer into the ClutterContent delegate!
    if (pixbuf != NULL) {
        clutter_image_set_data(CLUTTER_IMAGE(colors),
                               gdk_pixbuf_get_pixels (pixbuf),
                               COGL_PIXEL_FORMAT_RGB_888,
                               gdk_pixbuf_get_width (pixbuf),
                               gdk_pixbuf_get_height (pixbuf),
                               gdk_pixbuf_get_rowstride (pixbuf),
                               &error);
    }
//    clutter_actor_set_content(lightDisplay, colors); // Bind that delegate to the lightDisplay


    // Update the shader uniforms:

    // Populate the audioImage with the FFT data:
//    executeFFT(audioPixels, audioRowstride);

    // Actually load our FFT Texture colors onto the actor
//    clutter_image_set_data (CLUTTER_IMAGE (audioImage),
//                            gdk_pixbuf_get_pixels (audiopixbuf),
//                            gdk_pixbuf_get_has_alpha (audiopixbuf)
//                            ? COGL_PIXEL_FORMAT_RGBA_8888
//                            : COGL_PIXEL_FORMAT_RGB_888,
//                            gdk_pixbuf_get_width (audiopixbuf),
//                            gdk_pixbuf_get_height (audiopixbuf),
//                            gdk_pixbuf_get_rowstride (audiopixbuf),
//                            &error);
//    clutter_actor_set_content (shaderOutput, audioImage);


    // Use the timeline delta to determine how much time to add to the clock:
    int delta = clutter_timeline_get_delta(timeline);
    if (animation->currentSpeed > 500 || animation->currentSpeed<-500) {
        animation->currentSpeed = 100;
    }
    animationTime += delta/1000.0 * (animation->currentSpeed/100.0);
//    printf("Current speed: %i, animation time: %f\n", animation->currentSpeed, animationTime);

    // Update the random noiseImage:
//    for (unsigned int i=0; i<noiseTextureSize; i++) {
//        noiseTexture[i] = getrandf();
//    }

    if (animation->shaderLoaded ) { // Only update the shader when a shader is actually SET
        clutter_shader_effect_set_uniform(CLUTTER_SHADER_EFFECT(shaderEffect), "iGlobalTime", G_TYPE_FLOAT, 1, animationTime);
        clutter_shader_effect_set_uniform(CLUTTER_SHADER_EFFECT(shaderEffect), "iMouse", G_TYPE_FLOAT, 2, input_y*1.0, input_x*1.0);
    }

}