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_seconds
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>
gdk_threads_lock
gdk_threads_unlock

189
gdk/gdk.c
View File

@@ -1,5 +1,6 @@
/* GDK - The GIMP Drawing Kit
* 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
* 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 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_unlock = NULL;
@@ -809,3 +811,190 @@ gdk_enable_multidevice (void)
_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_seconds
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

View File

@@ -1,5 +1,6 @@
/* GDK - The GIMP Drawing Kit
* 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
* 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,
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_LEAVE() gdk_threads_leave()

View File

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

View File

@@ -1068,6 +1068,9 @@ gtk_init_check (int *argc,
if (!gtk_parse_args (argc, argv))
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;
}

View File

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