mutter/clutter/clutter-frame-source.c
Neil Roberts 9144b3902e * clutter/clutter-frame-source.c (clutter_frame_source_add)
(clutter_frame_source_add_full): Add gtk-doc and rename the
	'function' parameter to 'func'.

	* clutter/clutter-frame-source.h: Rename the 'function' parameters
	to 'func'.

	* clutter/Makefile.am (source_h): Make clutter-frame-source.h a
	public header.

	* clutter/clutter-main.c (clutter_threads_add_frame_source_full):
	Improve gtk-doc

	* doc/reference/clutter/clutter-sections.txt: Added
	clutter_threads_add_frame_source,
	clutter_threads_add_frame_source_full,
	clutter_frame_source_add and clutter_frame_source_add_full.
2008-05-09 16:27:06 +00:00

199 lines
5.8 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2008 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-frame-source.h"
typedef struct _ClutterFrameSource ClutterFrameSource;
struct _ClutterFrameSource
{
GSource source;
GTimeVal start_time;
guint last_time, frame_time;
};
static gboolean clutter_frame_source_prepare (GSource *source, gint *timeout);
static gboolean clutter_frame_source_check (GSource *source);
static gboolean clutter_frame_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static GSourceFuncs clutter_frame_source_funcs =
{
clutter_frame_source_prepare,
clutter_frame_source_check,
clutter_frame_source_dispatch,
NULL
};
/**
* clutter_frame_source_add_full:
* @priority: the priority of the frame source. Typically this will be in the
* range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
* @interval: the time between calls to the function, in milliseconds
* @func: function to call
* @data: data to pass to the function
* @notify: function to call when the timeout source is removed
*
* Sets a function to be called at regular intervals with the given
* priority. The function is called repeatedly until it returns
* %FALSE, at which point the timeout is automatically destroyed and
* the function will not be called again. The @notify function is
* called when the timeout is destroyed. The first call to the
* function will be at the end of the first @interval.
*
* This function is similar to g_timeout_add_full() except that it
* will try to compensate for delays. For example, if @func takes half
* the interval time to execute then the function will be called again
* half the interval time after it finished. In contrast
* g_timeout_add_full() would not fire until a full interval after the
* function completes so the delay between calls would be @interval *
* 1.5. This function does not however try to invoke the function
* multiple times to catch up missing frames if @func takes more than
* @interval ms to execute.
*
* Return value: the ID (greater than 0) of the event source.
*
* Since: 0.8
*/
guint
clutter_frame_source_add_full (gint priority,
guint interval,
GSourceFunc func,
gpointer data,
GDestroyNotify notify)
{
guint ret;
GSource *source = g_source_new (&clutter_frame_source_funcs,
sizeof (ClutterFrameSource));
ClutterFrameSource *frame_source = (ClutterFrameSource *) source;
frame_source->last_time = 0;
frame_source->frame_time = interval;
g_get_current_time (&frame_source->start_time);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (source, priority);
g_source_set_callback (source, func, data, notify);
ret = g_source_attach (source, NULL);
g_source_unref (source);
return ret;
}
/**
* clutter_frame_source_add:
* @interval: the time between calls to the function, in milliseconds
* @func: function to call
* @data: data to pass to the function
*
* Simple wrapper around clutter_frame_source_add_full().
*
* Return value: the ID (greater than 0) of the event source.
*
* Since: 0.8
*/
guint
clutter_frame_source_add (guint interval,
GSourceFunc func,
gpointer data)
{
return clutter_frame_source_add_full (G_PRIORITY_DEFAULT,
interval, func, data, NULL);
}
static guint
clutter_frame_source_get_ticks (ClutterFrameSource *frame_source)
{
GTimeVal time_now;
g_source_get_current_time ((GSource *) frame_source, &time_now);
return (time_now.tv_sec - frame_source->start_time.tv_sec) * 1000
+ (time_now.tv_usec - frame_source->start_time.tv_usec) / 1000;
}
static gboolean
clutter_frame_source_prepare (GSource *source, gint *timeout)
{
ClutterFrameSource *frame_source = (ClutterFrameSource *) source;
guint now = clutter_frame_source_get_ticks (frame_source);
/* If time has gone backwards or the time since the last frame is
greater than the two frames worth then reset the time and do a
frame now */
if (frame_source->last_time > now ||
(now - frame_source->last_time) > frame_source->frame_time * 2)
{
frame_source->last_time = now - frame_source->frame_time;
if (timeout)
*timeout = 0;
return TRUE;
}
else if (now - frame_source->last_time >= frame_source->frame_time)
{
if (timeout)
*timeout = 0;
return TRUE;
}
else
{
if (timeout)
*timeout = frame_source->frame_time + frame_source->last_time - now;
return FALSE;
}
}
static gboolean
clutter_frame_source_check (GSource *source)
{
return clutter_frame_source_prepare (source, NULL);
}
static gboolean
clutter_frame_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterFrameSource *frame_source = (ClutterFrameSource *) source;
if ((* callback) (user_data))
{
frame_source->last_time += frame_source->frame_time;
return TRUE;
}
else
return FALSE;
}