Compare commits

...

5 Commits

Author SHA1 Message Date
Ryan Lortie
c52cbb18d6 GtkSpiner: adjust to minor GPeriodic change
The timestamp to the tick function is now in microseconds instead of
milliticks.
2010-10-21 01:40:01 +02:00
Ryan Lortie
85608e903f GtkSpinner: animate with GPeriodic via gdk_threads
As a proof of concept, replace the timeout in the GtkSpinner code with a
GDK periodic callback.
2010-10-20 13:51:49 +02:00
Ryan Lortie
55b2f3ab4e GdkWindow: Use GPeriodic to repaint windows
Replace the invalidation idle function with a damage registration inside
GPeriodic, using the GDK thread functions.
2010-10-20 13:51:49 +02:00
Ryan Lortie
079366259a gtk_init(): initialise the GDK global GPeriodic
Initialise the GDK global periodic clock object from gtk_init() if
nobody installed one before us.
2010-10-20 13:51:49 +02:00
Ryan Lortie
76db970f8e GDK threads: store a global GPeriodic object
Add support to GDK for storing a global GPeriodic object.

Add some convenience functions for registering tick and repair functions
that run with the GDK lock held.
2010-10-20 13:51:49 +02:00
7 changed files with 248 additions and 49 deletions

View File

@@ -632,7 +632,12 @@ gdk_threads_add_timeout
gdk_threads_add_timeout_full gdk_threads_add_timeout_full
gdk_threads_add_timeout_seconds gdk_threads_add_timeout_seconds
gdk_threads_add_timeout_seconds_full gdk_threads_add_timeout_seconds_full
<SUBSECTION>
gdk_threads_get_periodic
gdk_threads_set_periodic
gdk_threads_periodic_add
gdk_threads_periodic_remove
gdk_threads_periodic_damaged
<SUBSECTION Private> <SUBSECTION Private>
gdk_threads_lock gdk_threads_lock
gdk_threads_unlock gdk_threads_unlock

189
gdk/gdk.c
View File

@@ -1,5 +1,6 @@
/* GDK - The GIMP Drawing Kit /* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright © 2010 Codethink Limited
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -65,6 +66,7 @@ static int gdk_initialized = 0; /* 1 if the library is initialized,
static gchar *gdk_progclass = NULL; static gchar *gdk_progclass = NULL;
static GMutex *gdk_threads_mutex = NULL; /* Global GDK lock */ static GMutex *gdk_threads_mutex = NULL; /* Global GDK lock */
static GPeriodic *gdk_threads_periodic; /* Default paint clock */
static GCallback gdk_threads_lock = NULL; static GCallback gdk_threads_lock = NULL;
static GCallback gdk_threads_unlock = NULL; static GCallback gdk_threads_unlock = NULL;
@@ -809,3 +811,190 @@ gdk_enable_multidevice (void)
_gdk_enable_multidevice = TRUE; _gdk_enable_multidevice = TRUE;
} }
/**
* gdk_threads_set_periodic:
* @periodic: a #GPeriodic, non-%NULL
*
* Sets the default #GPeriodic clock in use by GDK. GDK takes a
* reference on @periodic and it lives forever.
*
* You may not replace the default #GPeriodic once it has been set, so
* you should check with gdk_threads_get_periodic() to ensure that it is
* %NULL before attempting to call this function.
*
* gtk_init() will set the default clock if it has not already been set,
* so you need to call this function before you call gtk_init().
*
* Since: 3.0
**/
void
gdk_threads_set_periodic (GPeriodic *periodic)
{
g_return_if_fail (gdk_threads_periodic == NULL);
g_return_if_fail (periodic != NULL);
gdk_threads_periodic = g_object_ref (periodic);
}
/**
* gdk_threads_get_periodic:
*
* Gets the default #GPeriodic in use by GDK, or %NULL if one has not
* been set yet.
*
* GDK owns the return value, so you should not unref it.
*
* Returns: (transfer none): the default #GPeriodic, or %NULL
*
* Since: 3.0
**/
GPeriodic *
gdk_threads_get_periodic (void)
{
return gdk_threads_periodic;
}
typedef struct
{
GPeriodicTickFunc callback;
gpointer user_data;
GDestroyNotify notify;
} GdkPeriodicTick;
static void
gdk_periodic_tick (GPeriodic *periodic,
guint64 timestamp,
gpointer user_data)
{
GdkPeriodicTick *tick = user_data;
gdk_threads_enter ();
tick->callback (periodic, timestamp, tick->user_data);
/* Do not touch 'tick' anymore.
* It might have been freed by the callback removing itself.
*/
gdk_threads_leave ();
}
static void
gdk_periodic_tick_free (gpointer data)
{
GdkPeriodicTick *tick = data;
if (tick->notify)
tick->notify (tick->user_data);
g_slice_free (GdkPeriodicTick, tick);
}
/**
* gdk_threads_periodic_add:
* @callback: a #GPeriodicTickFunc
* @user_data: data for @callback
* @notify: for freeing @user_data when it is no longer needed
*
* Request periodic calls to @callback to start. @callback is called
* with the GDK lock held.
*
* This function may not be called while a repair function is running,
* but it is perfectly reasonable to call it from a tick function.
*
* The callback may be cancelled later by using
* gdk_threads_periodic_remove().
*
* Returns: a non-zero tag identifying this callback
*
* Since: 3.0
**/
guint
gdk_threads_periodic_add (GPeriodicTickFunc callback,
gpointer user_data,
GDestroyNotify notify)
{
GdkPeriodicTick *tick;
tick = g_slice_new (GdkPeriodicTick);
tick->callback = callback;
tick->user_data = user_data;
tick->notify = notify;
return g_periodic_add (gdk_threads_periodic, gdk_periodic_tick,
tick, gdk_periodic_tick_free);
}
/**
* gdk_threads_periodic_remove:
* @tag: the ID of the callback to
*
* Reverse the effect of a previous call to gdk_threads_periodic_add().
*
* @tag is the ID returned by that function.
*
* This function may not be called while a repair function is running,
* but it is perfectly reasonable to call it from a tick function.
*
* Since: 3.0
**/
void
gdk_threads_periodic_remove (guint tag)
{
g_periodic_remove (gdk_threads_periodic, tag);
}
typedef struct
{
GPeriodicRepairFunc callback;
gpointer user_data;
GDestroyNotify notify;
} GdkPeriodicRepair;
static void
gdk_periodic_repair (GPeriodic *periodic,
gpointer user_data)
{
GdkPeriodicRepair *repair = user_data;
gdk_threads_enter ();
repair->callback (periodic, repair->user_data);
gdk_threads_leave ();
}
static void
gdk_periodic_repair_free (gpointer data)
{
GdkPeriodicRepair *repair = data;
if (repair->notify)
repair->notify (repair->user_data);
g_slice_free (GdkPeriodicRepair, repair);
}
/**
* gdk_threads_periodic_damaged:
* @callback: a #GPeriodicRepairFunc
* @user_data: data for @callback
* @notify: for freeing @user_data when it is no longer needed
*
* Reports damage to the GDK default #GPeriodic.
*
* @callback is called with the GDK lock held.
*
* Since: 3.0
**/
void
gdk_threads_periodic_damaged (GPeriodicRepairFunc callback,
gpointer user_data,
GDestroyNotify notify)
{
GdkPeriodicRepair *repair;
repair = g_slice_new (GdkPeriodicRepair);
repair->callback = callback;
repair->user_data = user_data;
repair->notify = notify;
g_periodic_damaged (gdk_threads_periodic, gdk_periodic_repair,
repair, gdk_periodic_repair_free);
}

View File

@@ -192,6 +192,11 @@ gdk_threads_add_timeout
gdk_threads_add_timeout_full gdk_threads_add_timeout_full
gdk_threads_add_timeout_seconds gdk_threads_add_timeout_seconds
gdk_threads_add_timeout_seconds_full gdk_threads_add_timeout_seconds_full
gdk_threads_set_periodic
gdk_threads_get_periodic
gdk_threads_periodic_add
gdk_threads_periodic_remove
gdk_threads_periodic_damaged
#endif #endif
#endif #endif

View File

@@ -1,5 +1,6 @@
/* GDK - The GIMP Drawing Kit /* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright © 2010 Codethink Limited
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -64,6 +65,16 @@ guint gdk_threads_add_timeout_seconds (guint interval,
GSourceFunc function, GSourceFunc function,
gpointer data); gpointer data);
void gdk_threads_set_periodic (GPeriodic *periodic);
GPeriodic * gdk_threads_get_periodic (void);
guint gdk_threads_periodic_add (GPeriodicTickFunc callback,
gpointer user_data,
GDestroyNotify notify);
void gdk_threads_periodic_remove (guint tag);
void gdk_threads_periodic_damaged (GPeriodicRepairFunc callback,
gpointer user_data,
GDestroyNotify notify);
#define GDK_THREADS_ENTER() gdk_threads_enter() #define GDK_THREADS_ENTER() gdk_threads_enter()
#define GDK_THREADS_LEAVE() gdk_threads_leave() #define GDK_THREADS_LEAVE() gdk_threads_leave()

View File

@@ -3760,7 +3760,7 @@ gdk_window_set_cairo_clip (GdkDrawable *drawable,
/* Code for dirty-region queueing /* Code for dirty-region queueing
*/ */
static GSList *update_windows = NULL; static GSList *update_windows = NULL;
static guint update_idle = 0; static gboolean damage_reported;
static gboolean debug_updates = FALSE; static gboolean debug_updates = FALSE;
static inline gboolean static inline gboolean
@@ -3859,12 +3859,12 @@ gdk_window_remove_update_window (GdkWindow *window)
update_windows = g_slist_remove (update_windows, window); update_windows = g_slist_remove (update_windows, window);
} }
static gboolean static void
gdk_window_update_idle (gpointer data) gdk_window_repair (GPeriodic *periodic,
gpointer user_data)
{ {
gdk_window_process_all_updates (); gdk_window_process_all_updates ();
damage_reported = FALSE;
return FALSE;
} }
static gboolean static gboolean
@@ -3885,11 +3885,11 @@ gdk_window_schedule_update (GdkWindow *window)
gdk_window_is_toplevel_frozen (window))) gdk_window_is_toplevel_frozen (window)))
return; return;
if (!update_idle) if (!damage_reported)
update_idle = {
gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW, gdk_threads_periodic_damaged (gdk_window_repair, NULL, NULL);
gdk_window_update_idle, damage_reported = TRUE;
NULL, NULL); }
} }
void void
@@ -4212,18 +4212,15 @@ gdk_window_process_all_updates (void)
/* We can't do this now since that would recurse, so /* We can't do this now since that would recurse, so
delay it until after the recursion is done. */ delay it until after the recursion is done. */
got_recursive_update = TRUE; got_recursive_update = TRUE;
update_idle = 0;
return; return;
} }
in_process_all_updates = TRUE; in_process_all_updates = TRUE;
got_recursive_update = FALSE; got_recursive_update = FALSE;
if (update_idle) /* We can't unreport damage, so let it run anyway. */
g_source_remove (update_idle);
update_windows = NULL; update_windows = NULL;
update_idle = 0;
_gdk_windowing_before_process_all_updates (); _gdk_windowing_before_process_all_updates ();
@@ -4258,11 +4255,11 @@ gdk_window_process_all_updates (void)
redraw now so that it eventually happens, redraw now so that it eventually happens,
otherwise we could miss an update if nothing otherwise we could miss an update if nothing
else schedules an update. */ else schedules an update. */
if (got_recursive_update && !update_idle) if (got_recursive_update && !damage_reported)
update_idle = {
gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW, gdk_threads_periodic_damaged (gdk_window_repair, NULL, NULL);
gdk_window_update_idle, damage_reported = TRUE;
NULL, NULL); }
} }
/** /**

View File

@@ -1068,6 +1068,9 @@ gtk_init_check (int *argc,
if (!gtk_parse_args (argc, argv)) if (!gtk_parse_args (argc, argv))
return FALSE; return FALSE;
if (gdk_threads_get_periodic () == NULL)
gdk_threads_set_periodic (g_periodic_new (60, GDK_PRIORITY_REDRAW));
return gdk_display_open_default_libgtk_only () != NULL; return gdk_display_open_default_libgtk_only () != NULL;
} }

View File

@@ -66,7 +66,7 @@ struct _GtkSpinnerPrivate
guint num_steps; guint num_steps;
guint cycle_duration; guint cycle_duration;
gboolean active; gboolean active;
guint timeout; guint tag;
}; };
static void gtk_spinner_dispose (GObject *gobject); static void gtk_spinner_dispose (GObject *gobject);
@@ -211,9 +211,6 @@ gtk_spinner_init (GtkSpinner *spinner)
priv = G_TYPE_INSTANCE_GET_PRIVATE (spinner, priv = G_TYPE_INSTANCE_GET_PRIVATE (spinner,
GTK_TYPE_SPINNER, GTK_TYPE_SPINNER,
GtkSpinnerPrivate); GtkSpinnerPrivate);
priv->current = 0;
priv->timeout = 0;
spinner->priv = priv; spinner->priv = priv;
gtk_widget_set_has_window (GTK_WIDGET (spinner), FALSE); gtk_widget_set_has_window (GTK_WIDGET (spinner), FALSE);
@@ -269,42 +266,34 @@ gtk_spinner_draw (GtkWidget *widget,
return FALSE; return FALSE;
} }
static gboolean static void
gtk_spinner_timeout (gpointer data) gtk_spinner_tick (GPeriodic *periodic,
guint64 timestamp,
gpointer user_data)
{ {
GtkSpinnerPrivate *priv; GtkSpinnerPrivate *priv;
guint duration;
priv = GTK_SPINNER (data)->priv; priv = GTK_SPINNER (user_data)->priv;
if (priv->current + 1 >= priv->num_steps) duration = priv->cycle_duration * 1000;
priv->current = 0; priv->current = (timestamp % duration) / (duration / priv->num_steps);
else
priv->current++;
gtk_widget_queue_draw (GTK_WIDGET (data)); gtk_widget_queue_draw (GTK_WIDGET (user_data));
return TRUE;
} }
static void static void
gtk_spinner_add_timeout (GtkSpinner *spinner) gtk_spinner_add_timeout (GtkSpinner *spinner)
{ {
GtkSpinnerPrivate *priv; spinner->priv->tag =
gdk_threads_periodic_add (gtk_spinner_tick, spinner, NULL);
priv = spinner->priv;
priv->timeout = gdk_threads_add_timeout ((guint) priv->cycle_duration / priv->num_steps, gtk_spinner_timeout, spinner);
} }
static void static void
gtk_spinner_remove_timeout (GtkSpinner *spinner) gtk_spinner_remove_timeout (GtkSpinner *spinner)
{ {
GtkSpinnerPrivate *priv; gdk_threads_periodic_remove (spinner->priv->tag);
spinner->priv->tag = 0;
priv = spinner->priv;
g_source_remove (priv->timeout);
priv->timeout = 0;
} }
static void static void
@@ -325,7 +314,7 @@ gtk_spinner_unmap (GtkWidget *widget)
GtkSpinner *spinner = GTK_SPINNER (widget); GtkSpinner *spinner = GTK_SPINNER (widget);
GtkSpinnerPrivate *priv = spinner->priv; GtkSpinnerPrivate *priv = spinner->priv;
if (priv->timeout != 0) if (priv->tag != 0)
gtk_spinner_remove_timeout (spinner); gtk_spinner_remove_timeout (spinner);
GTK_WIDGET_CLASS (gtk_spinner_parent_class)->unmap (widget); GTK_WIDGET_CLASS (gtk_spinner_parent_class)->unmap (widget);
@@ -355,7 +344,7 @@ gtk_spinner_dispose (GObject *gobject)
priv = GTK_SPINNER (gobject)->priv; priv = GTK_SPINNER (gobject)->priv;
if (priv->timeout != 0) if (priv->tag != 0)
{ {
gtk_spinner_remove_timeout (GTK_SPINNER (gobject)); gtk_spinner_remove_timeout (GTK_SPINNER (gobject));
} }
@@ -377,11 +366,11 @@ gtk_spinner_set_active (GtkSpinner *spinner, gboolean active)
priv->active = active; priv->active = active;
g_object_notify (G_OBJECT (spinner), "active"); g_object_notify (G_OBJECT (spinner), "active");
if (active && gtk_widget_get_realized (GTK_WIDGET (spinner)) && priv->timeout == 0) if (active && gtk_widget_get_realized (GTK_WIDGET (spinner)) && priv->tag == 0)
{ {
gtk_spinner_add_timeout (spinner); gtk_spinner_add_timeout (spinner);
} }
else if (!active && priv->timeout != 0) else if (!active && priv->tag != 0)
{ {
gtk_spinner_remove_timeout (spinner); gtk_spinner_remove_timeout (spinner);
} }