mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
Merge clutter.git/threading branch
This commit is contained in:
parent
f5b4b96394
commit
4befcd0a64
37
ChangeLog
37
ChangeLog
@ -1,3 +1,40 @@
|
||||
2007-08-08 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
Merge the clutter.git/threading branch.
|
||||
|
||||
* clutter/clutter-main.c:
|
||||
* clutter/clutter-main.h:
|
||||
* clutter/clutter-private.h: Add threading locking and unlocking
|
||||
functions, to mark a critical section and access the Clutter API
|
||||
from differen threads. Add an initialisation function and a function
|
||||
to override the default lock aquisition and release functions, for
|
||||
bindings and application-specific locking handling. Add MT-safe
|
||||
versions of g_idle_add() and g_timeout_add() which will call the
|
||||
functions under the main Clutter lock and without races. The
|
||||
Clutter thread-safe implementation is basically the same used by
|
||||
GDK, so the same caveats apply.
|
||||
|
||||
* clutter/clutter-actor.c:
|
||||
* clutter/clutter-timeline.c:
|
||||
* clutter/clutter-timeout-pool.c: Use the new threading API when
|
||||
invoking idle and timeouts.
|
||||
|
||||
* clutter/eglnative/clutter-event-egl.c:
|
||||
* clutter/eglx/clutter-event-egl.c:
|
||||
* clutter/glx/clutter-event-glx.c:
|
||||
* clutter/sdl/clutter-event-sdl.c: Acquire and release the main
|
||||
Clutter lock when preparing, checking and dispatching the events
|
||||
on the queue in every backend.
|
||||
|
||||
* tests/Makefile.am:
|
||||
* tests/test-threads.c: Add a test case, showing how to use the
|
||||
threading API and write thread-safe Clutter applications.
|
||||
|
||||
2007-08-08 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* configure.ac: Bump up to 0.5.0 and start the new development
|
||||
branch.
|
||||
|
||||
2007-08-07 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* configure.ac: Bump up to 0.4.0.
|
||||
|
@ -1210,11 +1210,12 @@ clutter_actor_queue_redraw (ClutterActor *self)
|
||||
|
||||
if (!ctx->update_idle)
|
||||
{
|
||||
CLUTTER_TIMESTAMP (SCHEDULER,
|
||||
"Adding ideler for actor: %p", self);
|
||||
ctx->update_idle = g_idle_add_full (G_PRIORITY_DEFAULT + 10,
|
||||
redraw_update_idle,
|
||||
NULL, NULL);
|
||||
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for actor: %p", self);
|
||||
|
||||
ctx->update_idle =
|
||||
clutter_threads_add_idle_full (G_PRIORITY_DEFAULT + 10,
|
||||
redraw_update_idle,
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,12 +48,21 @@
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
/* main context */
|
||||
static ClutterMainContext *ClutterCntx = NULL;
|
||||
|
||||
/* main lock and locking/unlocking functions */
|
||||
static GMutex *clutter_threads_mutex = NULL;
|
||||
static GCallback clutter_threads_lock = NULL;
|
||||
static GCallback clutter_threads_unlock = NULL;
|
||||
|
||||
static gboolean clutter_is_initialized = FALSE;
|
||||
static gboolean clutter_show_fps = FALSE;
|
||||
static gboolean clutter_fatal_warnings = FALSE;
|
||||
|
||||
static guint clutter_main_loop_level = 0;
|
||||
static GSList *main_loops = NULL;
|
||||
|
||||
guint clutter_debug_flags = 0; /* global clutter debug flag */
|
||||
|
||||
#ifdef CLUTTER_ENABLE_DEBUG
|
||||
@ -75,9 +84,12 @@ static const GDebugKey clutter_debug_keys[] = {
|
||||
/**
|
||||
* clutter_get_show_fps:
|
||||
*
|
||||
* FIXME
|
||||
* Returns whether Clutter should print out the frames per second on the
|
||||
* console. You can enable this setting either using the
|
||||
* <literal>CLUTTER_SHOW_FPS</literal> environment variable or passing
|
||||
* the <literal>--clutter-show-fps</literal> command line argument. *
|
||||
*
|
||||
* Return value: FIXME
|
||||
* Return value: %TRUE if Clutter should show the FPS.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
@ -91,7 +103,8 @@ clutter_get_show_fps (void)
|
||||
/**
|
||||
* clutter_redraw:
|
||||
*
|
||||
* FIXME
|
||||
* Forces a redraw of the entire stage. Applications should never use this
|
||||
* function, but queue a redraw using clutter_actor_queue_redraw().
|
||||
*/
|
||||
void
|
||||
clutter_redraw (void)
|
||||
@ -161,8 +174,11 @@ clutter_redraw (void)
|
||||
|
||||
/**
|
||||
* clutter_do_event
|
||||
* @event: a #ClutterEvent.
|
||||
*
|
||||
* This function should never be called by applications.
|
||||
* Processes an event. This function should never be called by applications.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_do_event (ClutterEvent *event)
|
||||
@ -215,12 +231,9 @@ clutter_do_event (ClutterEvent *event)
|
||||
void
|
||||
clutter_main_quit (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
g_return_if_fail (main_loops != NULL);
|
||||
|
||||
g_return_if_fail (context->main_loops != NULL);
|
||||
|
||||
if (g_main_loop_is_running (context->main_loops->data))
|
||||
g_main_loop_quit (context->main_loops->data);
|
||||
g_main_loop_quit (main_loops->data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,9 +246,7 @@ clutter_main_quit (void)
|
||||
gint
|
||||
clutter_main_level (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
|
||||
return context->main_loop_level;
|
||||
return clutter_main_loop_level;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,24 +269,25 @@ clutter_main (void)
|
||||
|
||||
CLUTTER_MARK ();
|
||||
|
||||
context->main_loop_level++;
|
||||
clutter_main_loop_level++;
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
context->main_loops = g_slist_prepend (context->main_loops, loop);
|
||||
main_loops = g_slist_prepend (main_loops, loop);
|
||||
|
||||
if (g_main_loop_is_running (context->main_loops->data))
|
||||
if (g_main_loop_is_running (main_loops->data))
|
||||
{
|
||||
/* FIXME - add thread locking around this call */
|
||||
clutter_threads_leave ();
|
||||
g_main_loop_run (loop);
|
||||
clutter_threads_enter ();
|
||||
}
|
||||
|
||||
context->main_loops = g_slist_remove (context->main_loops, loop);
|
||||
main_loops = g_slist_remove (main_loops, loop);
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
context->main_loop_level--;
|
||||
clutter_main_loop_level--;
|
||||
|
||||
if (context->main_loop_level == 0)
|
||||
if (clutter_main_loop_level == 0)
|
||||
{
|
||||
/* this will take care of destroying the stage */
|
||||
g_object_unref (context->backend);
|
||||
@ -287,6 +299,326 @@ clutter_main (void)
|
||||
CLUTTER_MARK ();
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_threads_impl_lock (void)
|
||||
{
|
||||
if (clutter_threads_mutex)
|
||||
g_mutex_lock (clutter_threads_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_threads_impl_unlock (void)
|
||||
{
|
||||
if (clutter_threads_mutex)
|
||||
g_mutex_unlock (clutter_threads_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_init:
|
||||
*
|
||||
* Initialises the Clutter threading mechanism, so that Clutter API can be
|
||||
* called by multiple threads, using clutter_threads_enter() and
|
||||
* clutter_threads_leave() to mark the critical sections.
|
||||
*
|
||||
* You must call g_thread_init() before this function.
|
||||
*
|
||||
* This function must be called before clutter_init().
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
clutter_threads_init (void)
|
||||
{
|
||||
if (!g_thread_supported ())
|
||||
g_error ("g_thread_init() must be called before clutter_threads_init()");
|
||||
|
||||
clutter_threads_mutex = g_mutex_new ();
|
||||
|
||||
if (!clutter_threads_lock)
|
||||
clutter_threads_lock = clutter_threads_impl_lock;
|
||||
|
||||
if (!clutter_threads_unlock)
|
||||
clutter_threads_unlock = clutter_threads_impl_unlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_set_lock_functions:
|
||||
* @enter_fn: function called when aquiring the Clutter main lock
|
||||
* @leave_fn: function called when releasing the Clutter main lock
|
||||
*
|
||||
* Allows the application to replace the standard method that
|
||||
* Clutter uses to protect its data structures. Normally, Clutter
|
||||
* creates a single #GMutex that is locked by clutter_threads_enter(),
|
||||
* and released by clutter_threads_leave(); using this function an
|
||||
* application provides, instead, a function @enter_fn that is
|
||||
* called by clutter_threads_enter() and a function @leave_fn that is
|
||||
* called by clutter_threads_leave().
|
||||
*
|
||||
* The functions must provide at least same locking functionality
|
||||
* as the default implementation, but can also do extra application
|
||||
* specific processing.
|
||||
*
|
||||
* As an example, consider an application that has its own recursive
|
||||
* lock that when held, holds the Clutter lock as well. When Clutter
|
||||
* unlocks the Clutter lock when entering a recursive main loop, the
|
||||
* application must temporarily release its lock as well.
|
||||
*
|
||||
* Most threaded Clutter apps won't need to use this method.
|
||||
*
|
||||
* This method must be called before clutter_threads_init(), and cannot
|
||||
* be called multiple times.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
clutter_threads_set_lock_functions (GCallback enter_fn,
|
||||
GCallback leave_fn)
|
||||
{
|
||||
g_return_if_fail (clutter_threads_lock == NULL &&
|
||||
clutter_threads_unlock == NULL);
|
||||
|
||||
clutter_threads_lock = enter_fn;
|
||||
clutter_threads_unlock = leave_fn;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSourceFunc func;
|
||||
gpointer data;
|
||||
GDestroyNotify notify;
|
||||
} ClutterThreadsDispatch;
|
||||
|
||||
static gboolean
|
||||
clutter_threads_dispatch (gpointer data)
|
||||
{
|
||||
ClutterThreadsDispatch *dispatch = data;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (!g_source_is_destroyed (g_main_current_source ()))
|
||||
ret = dispatch->func (dispatch->data);
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_threads_dispatch_free (gpointer data)
|
||||
{
|
||||
ClutterThreadsDispatch *dispatch = data;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (dispatch->notify)
|
||||
dispatch->notify (dispatch->data);
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
g_slice_free (ClutterThreadsDispatch, dispatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_add_idle_full:
|
||||
* @priority: the priority of the timeout source. Typically this will be in the
|
||||
* range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
|
||||
* @func: function to call
|
||||
* @data: data to pass to the function
|
||||
* @notify: functio to call when the idle source is removed
|
||||
*
|
||||
* Adds a function to be called whenever there are no higher priority
|
||||
* events pending. If the function returns %FALSE it is automatically
|
||||
* removed from the list of event sources and will not be called again.
|
||||
*
|
||||
* This variant of g_idle_add_full() calls @function with the Clutter lock
|
||||
* held. It can be thought of a MT-safe version for Clutter actors for the
|
||||
* following use case, where you have to worry about idle_callback()
|
||||
* running in thread A and accessing @self after it has been finalized
|
||||
* in thread B:
|
||||
*
|
||||
* <informalexample><programlisting>
|
||||
* static gboolean
|
||||
* idle_callback (gpointer data)
|
||||
* {
|
||||
* // clutter_threads_enter(); would be needed for g_idle_add()
|
||||
*
|
||||
* SomeActor *self = data;
|
||||
* /<!-- -->* do stuff with self *<!-- -->/
|
||||
*
|
||||
* self->idle_id = 0;
|
||||
*
|
||||
* // clutter_threads_leave(); would be needed for g_idle_add()
|
||||
* return FALSE;
|
||||
* }
|
||||
* static void
|
||||
* some_actor_do_stuff_later (SomeActor *self)
|
||||
* {
|
||||
* self->idle_id = clutter_threads_add_idle (idle_callback, self)
|
||||
* // using g_idle_add() here would require thread protection in the callback
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* some_actor_finalize (GObject *object)
|
||||
* {
|
||||
* SomeActor *self = SOME_ACTOR (object);
|
||||
* if (self->idle_id)
|
||||
* g_source_remove (self->idle_id);
|
||||
* G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
* }
|
||||
* </programlisting></informalexample>
|
||||
*
|
||||
* Return value: the ID (greater than 0) of the event source.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_threads_add_idle_full (gint priority,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
ClutterThreadsDispatch *dispatch;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
dispatch = g_slice_new (ClutterThreadsDispatch);
|
||||
dispatch->func = func;
|
||||
dispatch->data = data;
|
||||
dispatch->notify = notify;
|
||||
|
||||
return g_idle_add_full (priority,
|
||||
clutter_threads_dispatch, dispatch,
|
||||
clutter_threads_dispatch_free);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_add_idle:
|
||||
* @func: function to call
|
||||
* @data: data to pass to the function
|
||||
*
|
||||
* Simple wrapper around clutter_threads_add_idle_full()
|
||||
*
|
||||
* Return value: the ID (greater than 0) of the event source.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_threads_add_idle (GSourceFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
return clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
|
||||
func, data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_add_timeout_full:
|
||||
* @priority: the priority of the timeout 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 holding the Clutter lock,
|
||||
* 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.
|
||||
*
|
||||
* Note that timeout functions may be delayed, due to the processing of other
|
||||
* event sources. Thus they should not be relied on for precise timing.
|
||||
* After each call to the timeout function, the time of the next
|
||||
* timeout is recalculated based on the current time and the given interval
|
||||
* (it does not try to 'catch up' time lost in delays).
|
||||
*
|
||||
* This variant of g_timeout_add_full() can be thought of a MT-safe version
|
||||
* for Clutter actors. See also clutter_threads_add_idle_full().
|
||||
*
|
||||
* Return value: the ID (greater than 0) of the event source.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_threads_add_timeout_full (gint priority,
|
||||
guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
ClutterThreadsDispatch *dispatch;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
dispatch = g_slice_new (ClutterThreadsDispatch);
|
||||
dispatch->func = func;
|
||||
dispatch->data = data;
|
||||
dispatch->notify = notify;
|
||||
|
||||
return g_timeout_add_full (priority,
|
||||
interval,
|
||||
clutter_threads_dispatch, dispatch,
|
||||
clutter_threads_dispatch_free);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_add_timeout:
|
||||
* @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_threads_add_timeout_full().
|
||||
*
|
||||
* Return value: the ID (greater than 0) of the event source.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_threads_add_timeout (guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
return clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT,
|
||||
interval,
|
||||
func, data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_enter:
|
||||
*
|
||||
* Locks the Clutter thread lock.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
clutter_threads_enter (void)
|
||||
{
|
||||
if (clutter_threads_lock)
|
||||
(* clutter_threads_lock) ();
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_leave:
|
||||
*
|
||||
* Unlocks the Clutter thread lock.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
clutter_threads_leave (void)
|
||||
{
|
||||
if (clutter_threads_unlock)
|
||||
(* clutter_threads_unlock) ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clutter_get_debug_enabled:
|
||||
*
|
||||
@ -410,8 +742,6 @@ pre_parse_hook (GOptionContext *context,
|
||||
return TRUE;
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
clutter_context->main_loops = NULL;
|
||||
clutter_context->main_loop_level = 0;
|
||||
|
||||
clutter_context->font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ());
|
||||
pango_ft2_font_map_set_resolution (clutter_context->font_map, 96.0, 96.0);
|
||||
@ -568,11 +898,11 @@ clutter_init_with_args (int *argc,
|
||||
if (clutter_is_initialized)
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
|
||||
clutter_base_init ();
|
||||
|
||||
if (argc && *argc > 0 && *argv)
|
||||
g_set_prgname ((*argv)[0]);
|
||||
|
||||
clutter_base_init ();
|
||||
|
||||
group = clutter_get_option_group ();
|
||||
context = g_option_context_new (parameter_string);
|
||||
|
||||
@ -664,10 +994,11 @@ clutter_init (int *argc,
|
||||
if (clutter_is_initialized)
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
|
||||
clutter_base_init ();
|
||||
|
||||
if (argc && *argc > 0 && *argv)
|
||||
g_set_prgname ((*argv)[0]);
|
||||
|
||||
clutter_base_init ();
|
||||
|
||||
/* parse_args will trigger backend creation and things like
|
||||
* DISPLAY connection etc.
|
||||
@ -734,6 +1065,8 @@ clutter_base_init (void)
|
||||
|
||||
/* initialise GLib type system */
|
||||
g_type_init ();
|
||||
|
||||
/* CLUTTER_TYPE_ACTOR */
|
||||
foo = clutter_actor_get_type ();
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ typedef enum {
|
||||
|
||||
GQuark clutter_init_error_quark (void);
|
||||
|
||||
/* Initialisation */
|
||||
void clutter_base_init (void);
|
||||
ClutterInitError clutter_init (int *argc,
|
||||
char ***argv);
|
||||
ClutterInitError clutter_init_with_args (int *argc,
|
||||
@ -63,22 +65,41 @@ ClutterInitError clutter_init_with_args (int *argc,
|
||||
GOptionEntry *entries,
|
||||
char *translation_domain,
|
||||
GError **error);
|
||||
|
||||
GOptionGroup * clutter_get_option_group (void);
|
||||
|
||||
void clutter_main (void);
|
||||
void clutter_main_quit (void);
|
||||
gint clutter_main_level (void);
|
||||
/* Mainloop */
|
||||
void clutter_main (void);
|
||||
void clutter_main_quit (void);
|
||||
gint clutter_main_level (void);
|
||||
|
||||
void clutter_redraw (void);
|
||||
void clutter_redraw (void);
|
||||
|
||||
gboolean clutter_get_debug_enabled (void);
|
||||
gboolean clutter_get_show_fps (void);
|
||||
/* Debug utility functions */
|
||||
gboolean clutter_get_debug_enabled (void);
|
||||
gboolean clutter_get_show_fps (void);
|
||||
gulong clutter_get_timestamp (void);
|
||||
|
||||
void clutter_base_init (void);
|
||||
|
||||
gulong clutter_get_timestamp (void);
|
||||
/* Threading functions */
|
||||
void clutter_threads_init (void);
|
||||
void clutter_threads_enter (void);
|
||||
void clutter_threads_leave (void);
|
||||
void clutter_threads_set_lock_functions (GCallback enter_fn,
|
||||
GCallback leave_fn);
|
||||
guint clutter_threads_add_idle (GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_idle_full (gint priority,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint clutter_threads_add_timeout (guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_timeout_full (gint priority,
|
||||
guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
#endif /* _HAVE_CLUTTER_MAIN_H */
|
||||
|
@ -47,15 +47,19 @@ typedef struct _ClutterMainContext ClutterMainContext;
|
||||
|
||||
struct _ClutterMainContext
|
||||
{
|
||||
/* holds a pointer to the stage */
|
||||
/* holds a pointer to the backend, which controls the stage */
|
||||
ClutterBackend *backend;
|
||||
|
||||
/* the main event queue */
|
||||
GQueue *events_queue;
|
||||
|
||||
PangoFT2FontMap *font_map;
|
||||
|
||||
guint update_idle;
|
||||
guint main_loop_level;
|
||||
GSList *main_loops;
|
||||
|
||||
guint is_initialized : 1;
|
||||
guint pick_mode :1; /* Indicates pick render mode */
|
||||
guint pick_mode : 1; /* Indicates pick render mode */
|
||||
|
||||
GTimer *timer; /* Used for debugging scheduler */
|
||||
};
|
||||
|
||||
|
@ -133,9 +133,9 @@ timeout_add (guint interval,
|
||||
}
|
||||
else
|
||||
{
|
||||
res = g_timeout_add_full (CLUTTER_TIMELINE_PRIORITY,
|
||||
interval,
|
||||
func, data, notify);
|
||||
res = clutter_threads_add_timeout_full (CLUTTER_TIMELINE_PRIORITY,
|
||||
interval,
|
||||
func, data, notify);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -183,12 +183,16 @@ static gboolean
|
||||
clutter_timeout_dispatch (GSource *source,
|
||||
ClutterTimeout *timeout)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
||||
if (G_UNLIKELY (!timeout->func))
|
||||
{
|
||||
g_warning ("Timeout dispatched without a callback.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (timeout->func (timeout->data))
|
||||
{
|
||||
GTimeVal current_time;
|
||||
@ -196,10 +200,12 @@ clutter_timeout_dispatch (GSource *source,
|
||||
g_source_get_current_time (source, ¤t_time);
|
||||
clutter_timeout_set_expiration (timeout, ¤t_time);
|
||||
|
||||
return TRUE;
|
||||
retval = TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ClutterTimeout *
|
||||
|
@ -150,10 +150,16 @@ clutter_event_prepare (GSource *source,
|
||||
gint *timeout)
|
||||
{
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
*timeout = -1;
|
||||
retval = clutter_events_pending ();
|
||||
|
||||
return clutter_events_pending ();
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -161,9 +167,16 @@ clutter_event_check (GSource *source)
|
||||
{
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
ClutterBackend *backend = event_source->backend;
|
||||
gboolean retval;
|
||||
|
||||
return ((event_source->event_poll_fd.revents & G_IO_IN)
|
||||
|| clutter_events_pending ());
|
||||
clutter_threads_enter ();
|
||||
|
||||
retval = ((event_source->event_poll_fd.revents & G_IO_IN) ||
|
||||
clutter_events_pending ());
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -178,6 +191,8 @@ clutter_event_dispatch (GSource *source,
|
||||
ClutterMainContext *clutter_context;
|
||||
static gint last_x, last_y;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
#ifdef HAVE_TSLIB
|
||||
/* FIXME while would be better here but need to deal with lockups */
|
||||
@ -189,8 +204,8 @@ clutter_event_dispatch (GSource *source,
|
||||
* event_button_generate gets confused generating lots of double
|
||||
* and triple clicks.
|
||||
*/
|
||||
if (tsevent.pressure && last_x == tsevent.x && last_y == tsevent.y)
|
||||
return;
|
||||
if (tsevent.pressure && last_x == tsevent.x && last_y == tsevent.y)
|
||||
goto out;
|
||||
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
|
||||
@ -223,5 +238,8 @@ clutter_event_dispatch (GSource *source,
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
out:
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -326,9 +326,13 @@ clutter_event_prepare (GSource *source,
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
*timeout = -1;
|
||||
retval = (clutter_events_pending () || clutter_check_xpending (backend));
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -339,10 +343,14 @@ clutter_event_check (GSource *source)
|
||||
ClutterBackend *backend = event_source->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (event_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = (clutter_events_pending () || clutter_check_xpending (backend));
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -355,6 +363,8 @@ clutter_event_dispatch (GSource *source,
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
ClutterEvent *event;
|
||||
|
||||
clutter_thread_enter ();
|
||||
|
||||
events_queue (backend);
|
||||
|
||||
event = clutter_event_get ();
|
||||
@ -365,5 +375,7 @@ clutter_event_dispatch (GSource *source,
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -549,9 +549,13 @@ clutter_event_prepare (GSource *source,
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
*timeout = -1;
|
||||
retval = (clutter_events_pending () || check_xpending (backend));
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -562,11 +566,15 @@ clutter_event_check (GSource *source)
|
||||
ClutterBackend *backend = event_source->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (event_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = (clutter_events_pending () || check_xpending (backend));
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -578,6 +586,8 @@ clutter_event_dispatch (GSource *source,
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
ClutterEvent *event;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
/* Grab the event(s), translate and figure out double click.
|
||||
* The push onto queue (stack) if valid.
|
||||
*/
|
||||
@ -593,5 +603,7 @@ clutter_event_dispatch (GSource *source,
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -112,11 +112,16 @@ clutter_event_prepare (GSource *source,
|
||||
{
|
||||
SDL_Event events;
|
||||
int num_events;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
num_events = SDL_PeepEvents(&events, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
|
||||
|
||||
if (num_events == 1)
|
||||
{
|
||||
clutter_threads_leave ();
|
||||
|
||||
*timeout = 0;
|
||||
return TRUE;
|
||||
}
|
||||
@ -126,7 +131,11 @@ clutter_event_prepare (GSource *source,
|
||||
|
||||
*timeout = 50;
|
||||
|
||||
return clutter_events_pending ();
|
||||
retval = clutter_events_pending ();
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -134,6 +143,9 @@ clutter_event_check (GSource *source)
|
||||
{
|
||||
SDL_Event events;
|
||||
int num_events;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
/* Pump SDL */
|
||||
SDL_PumpEvents();
|
||||
@ -143,7 +155,11 @@ clutter_event_check (GSource *source)
|
||||
if (num_events == -1)
|
||||
g_warning("Error polling SDL: %s", SDL_GetError());
|
||||
|
||||
return (num_events == 1 || clutter_events_pending ());
|
||||
retval = (num_events == 1 || clutter_events_pending ());
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -292,6 +308,8 @@ clutter_event_dispatch (GSource *source,
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
ClutterMainContext *clutter_context;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
|
||||
while (SDL_PollEvent(&sdl_event))
|
||||
@ -328,5 +346,7 @@ clutter_event_dispatch (GSource *source,
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
# An odd micro number indicates in-progress development, (eg. from CVS)
|
||||
# An even micro number indicates a released version.
|
||||
m4_define([clutter_major_version], [0])
|
||||
m4_define([clutter_minor_version], [4])
|
||||
m4_define([clutter_minor_version], [5])
|
||||
m4_define([clutter_micro_version], [0])
|
||||
|
||||
m4_define([clutter_version],
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-08-08 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter-sections.txt: Add the new clutter_threads_* API.
|
||||
|
||||
2007-08-07 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter-sections.txt: Shuffle around a bit the symbols.
|
||||
|
@ -828,12 +828,23 @@ ClutterInitError
|
||||
clutter_init
|
||||
clutter_init_with_args
|
||||
clutter_get_option_group
|
||||
clutter_get_debug_enabled
|
||||
clutter_get_show_fps
|
||||
<SUBSECTION>
|
||||
clutter_main
|
||||
clutter_main_quit
|
||||
clutter_main_level
|
||||
<SUBSECTION>
|
||||
clutter_get_debug_enabled
|
||||
clutter_get_show_fps
|
||||
clutter_get_timestamp
|
||||
<SUBSECTION>
|
||||
clutter_threads_set_lock_functions
|
||||
clutter_threads_init
|
||||
clutter_threads_enter
|
||||
clutter_threads_leave
|
||||
clutter_threads_add_idle
|
||||
clutter_threads_add_idle_full
|
||||
clutter_threads_add_timeout
|
||||
clutter_threads_add_timeout_full
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_INIT_ERROR
|
||||
<SUBSECTION Private>
|
||||
|
@ -1,6 +1,7 @@
|
||||
noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
|
||||
test-actors test-behave test-text test-entry test-project \
|
||||
test-boxes test-perspective test-rotate test-depth
|
||||
test-boxes test-perspective test-rotate test-depth \
|
||||
test-threads
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/
|
||||
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
@ -20,5 +21,6 @@ test_boxes_SOURCES = test-boxes.c
|
||||
test_perspective_SOURCES = test-perspective.c
|
||||
test_rotate_SOURCES = test-rotate.c
|
||||
test_depth_SOURCES = test-depth.c
|
||||
test_threads_SOURCES = test-threads.c
|
||||
|
||||
EXTRA_DIST = redhand.png
|
||||
|
@ -234,7 +234,7 @@ main (int argc, char *argv[])
|
||||
/* and start it */
|
||||
clutter_timeline_start (timeline);
|
||||
|
||||
clutter_main();
|
||||
clutter_main ();
|
||||
|
||||
g_free (oh->hand);
|
||||
g_free (oh);
|
||||
|
Loading…
Reference in New Issue
Block a user