diff options
author | Alexander Larsson <alexl@redhat.com> | 2007-11-16 12:55:14 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2007-11-16 12:55:14 +0000 |
commit | b5575ad4fd357c4e2e97166adb163c5d95ea7bbe (patch) | |
tree | be27794af6f4fce1ebe63e39aebc62736a742171 | |
parent | 144c3c5f701650cf9ddeff8de9431155954a48df (diff) | |
download | nautilus-b5575ad4fd357c4e2e97166adb163c5d95ea7bbe.tar.gz |
Reindent Fix threading issues wrt the idle source
2007-11-16 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-progress-info.c:
Reindent
Fix threading issues wrt the idle source
svn path=/branches/gio-branch/; revision=13423
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | libnautilus-private/nautilus-progress-info.c | 547 |
2 files changed, 309 insertions, 244 deletions
@@ -1,5 +1,11 @@ 2007-11-16 Alexander Larsson <alexl@redhat.com> + * libnautilus-private/nautilus-progress-info.c: + Reindent + Fix threading issues wrt the idle source + +2007-11-16 Alexander Larsson <alexl@redhat.com> + * libnautilus-private/Makefile.am: * libnautilus-private/nautilus-progress-info.[ch]: Added NautilusProgressInfo class diff --git a/libnautilus-private/nautilus-progress-info.c b/libnautilus-private/nautilus-progress-info.c index c7daf64c0..3f1f77cca 100644 --- a/libnautilus-private/nautilus-progress-info.c +++ b/libnautilus-private/nautilus-progress-info.c @@ -36,32 +36,35 @@ enum { LAST_SIGNAL }; +#define SIGNAL_DELAY_MSEC 2000 + static guint signals[LAST_SIGNAL] = { 0 }; struct _NautilusProgressInfo { - GObject parent_instance; - - GCancellable *cancellable; - - char *status; - char *details; - double progress; - gboolean activity_mode; - gboolean started; - gboolean finished; - - guint idle_tag; - - gboolean start_at_idle; - gboolean finish_at_idle; - gboolean changed_at_idle; - gboolean progress_at_idle; + GObject parent_instance; + + GCancellable *cancellable; + + char *status; + char *details; + double progress; + gboolean activity_mode; + gboolean started; + gboolean finished; + + GSource *idle_source; + gboolean source_is_now; + + gboolean start_at_idle; + gboolean finish_at_idle; + gboolean changed_at_idle; + gboolean progress_at_idle; }; struct _NautilusProgressInfoClass { - GObjectClass parent_class; + GObjectClass parent_class; }; @@ -72,296 +75,353 @@ G_DEFINE_TYPE (NautilusProgressInfo, nautilus_progress_info, G_TYPE_OBJECT) static void nautilus_progress_info_finalize (GObject *object) { - NautilusProgressInfo *info; - - info = NAUTILUS_PROGRESS_INFO (object); - - g_free (info->status); - g_free (info->details); - g_object_unref (info->cancellable); + NautilusProgressInfo *info; + + info = NAUTILUS_PROGRESS_INFO (object); + + g_free (info->status); + g_free (info->details); + g_object_unref (info->cancellable); + + if (G_OBJECT_CLASS (nautilus_progress_info_parent_class)->finalize) { + (*G_OBJECT_CLASS (nautilus_progress_info_parent_class)->finalize) (object); + } +} - /* idle refs info, so should never be outstanding at this point */ - g_assert (info->idle_tag == 0); - - if (G_OBJECT_CLASS (nautilus_progress_info_parent_class)->finalize) - (*G_OBJECT_CLASS (nautilus_progress_info_parent_class)->finalize) (object); +static void +nautilus_progress_info_dispose (GObject *object) +{ + NautilusProgressInfo *info; + + info = NAUTILUS_PROGRESS_INFO (object); + + /* Destroy source in dispose, because the callback + could come here before the destroy, which should + ressurect the object for a while */ + G_LOCK (progress_info); + if (info->idle_source) { + g_source_destroy (info->idle_source); + g_source_unref (info->idle_source); + info->idle_source = NULL; + } + G_UNLOCK (progress_info); } static void nautilus_progress_info_class_init (NautilusProgressInfoClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = nautilus_progress_info_finalize; - - signals[CHANGED] = - g_signal_new ("changed", - NAUTILUS_TYPE_PROGRESS_INFO, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[PROGRESS_CHANGED] = - g_signal_new ("progress-changed", - NAUTILUS_TYPE_PROGRESS_INFO, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[STARTED] = - g_signal_new ("started", - NAUTILUS_TYPE_PROGRESS_INFO, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[FINISHED] = - g_signal_new ("finished", - NAUTILUS_TYPE_PROGRESS_INFO, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = nautilus_progress_info_finalize; + gobject_class->dispose = nautilus_progress_info_dispose; + + signals[CHANGED] = + g_signal_new ("changed", + NAUTILUS_TYPE_PROGRESS_INFO, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[PROGRESS_CHANGED] = + g_signal_new ("progress-changed", + NAUTILUS_TYPE_PROGRESS_INFO, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[STARTED] = + g_signal_new ("started", + NAUTILUS_TYPE_PROGRESS_INFO, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[FINISHED] = + g_signal_new ("finished", + NAUTILUS_TYPE_PROGRESS_INFO, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + } static void nautilus_progress_info_init (NautilusProgressInfo *info) { - info->cancellable = g_cancellable_new (); + info->cancellable = g_cancellable_new (); } NautilusProgressInfo * nautilus_progress_info_new (void) { - NautilusProgressInfo *info; - - info = g_object_new (NAUTILUS_TYPE_PROGRESS_INFO, NULL); - - return info; + NautilusProgressInfo *info; + + info = g_object_new (NAUTILUS_TYPE_PROGRESS_INFO, NULL); + + return info; } char * nautilus_progress_info_get_status (NautilusProgressInfo *info) { - char *res; - - G_LOCK (progress_info); - - if (info->status) - res = g_strdup (info->status); - else - res = g_strdup (_("Preparing")); - - G_UNLOCK (progress_info); - - return res; + char *res; + + G_LOCK (progress_info); + + if (info->status) { + res = g_strdup (info->status); + } else { + res = g_strdup (_("Preparing")); + } + + G_UNLOCK (progress_info); + + return res; } char * nautilus_progress_info_get_details (NautilusProgressInfo *info) { - char *res; - - G_LOCK (progress_info); - - if (info->details) - res = g_strdup (info->details); - else - res = g_strdup (_("Preparing")); - - G_UNLOCK (progress_info); - - return res; + char *res; + + G_LOCK (progress_info); + + if (info->details) { + res = g_strdup (info->details); + } else { + res = g_strdup (_("Preparing")); + } + + G_UNLOCK (progress_info); + + return res; } double nautilus_progress_info_get_progress (NautilusProgressInfo *info) { - double res; - - G_LOCK (progress_info); - - res = info->progress; - - G_UNLOCK (progress_info); - - return res; + double res; + + G_LOCK (progress_info); + + res = info->progress; + + G_UNLOCK (progress_info); + + return res; } GCancellable * nautilus_progress_info_get_cancellable (NautilusProgressInfo *info) { - GCancellable *c; - - G_LOCK (progress_info); - - c = g_object_ref (info->cancellable); - - G_UNLOCK (progress_info); - - return c; + GCancellable *c; + + G_LOCK (progress_info); + + c = g_object_ref (info->cancellable); + + G_UNLOCK (progress_info); + + return c; } gboolean nautilus_progress_info_get_is_started (NautilusProgressInfo *info) { - gboolean res; - - G_LOCK (progress_info); - - res = info->started; - - G_UNLOCK (progress_info); - - return res; + gboolean res; + + G_LOCK (progress_info); + + res = info->started; + + G_UNLOCK (progress_info); + + return res; } gboolean nautilus_progress_info_get_is_finished (NautilusProgressInfo *info) { - gboolean res; - - G_LOCK (progress_info); - - res = info->finished; - - G_UNLOCK (progress_info); - - return res; + gboolean res; + + G_LOCK (progress_info); + + res = info->finished; + + G_UNLOCK (progress_info); + + return res; } static gboolean idle_callback (gpointer data) { - NautilusProgressInfo *info = data; - gboolean start_at_idle; - gboolean finish_at_idle; - gboolean changed_at_idle; - gboolean progress_at_idle; - - G_LOCK (progress_info); - - info->idle_tag = 0; - - start_at_idle = info->start_at_idle; - finish_at_idle = info->finish_at_idle; - changed_at_idle = info->changed_at_idle; - progress_at_idle = info->progress_at_idle; - - info->start_at_idle = FALSE; - info->finish_at_idle = FALSE; - info->changed_at_idle = FALSE; - info->progress_at_idle = FALSE; - - G_UNLOCK (progress_info); - - if (start_at_idle) - g_signal_emit (info, - STARTED, - 0); - - if (changed_at_idle) - g_signal_emit (info, - CHANGED, - 0); - - if (progress_at_idle) - g_signal_emit (info, - PROGRESS_CHANGED, - 0); - - if (finish_at_idle) - g_signal_emit (info, - FINISHED, - 0); - - g_object_unref (info); - - return FALSE; + NautilusProgressInfo *info = data; + gboolean start_at_idle; + gboolean finish_at_idle; + gboolean changed_at_idle; + gboolean progress_at_idle; + GSource *source; + + source = g_main_current_source (); + + G_LOCK (progress_info); + + /* Protect agains races where the source has + been destroyed on another thread while it + was being dispatched. + Similar to what gdk_threads_add_idle does. + */ + if (g_source_is_destroyed (source)) { + G_UNLOCK (progress_info); + return FALSE; + } + + /* We hadn't destroyed the source, so take a ref. + * This might ressurect the object from dispose, but + * that should be ok. + */ + g_object_ref (info); + + g_assert (source == info->idle_source); + + g_source_unref (source); + info->idle_source = NULL; + + start_at_idle = info->start_at_idle; + finish_at_idle = info->finish_at_idle; + changed_at_idle = info->changed_at_idle; + progress_at_idle = info->progress_at_idle; + + info->start_at_idle = FALSE; + info->finish_at_idle = FALSE; + info->changed_at_idle = FALSE; + info->progress_at_idle = FALSE; + + G_UNLOCK (progress_info); + + if (start_at_idle) { + g_signal_emit (info, + STARTED, + 0); + } + + if (changed_at_idle) { + g_signal_emit (info, + CHANGED, + 0); + } + + if (progress_at_idle) { + g_signal_emit (info, + PROGRESS_CHANGED, + 0); + } + + if (finish_at_idle) { + g_signal_emit (info, + FINISHED, + 0); + } + + g_object_unref (info); + + return FALSE; } /* Called with lock held */ static void -queue_idle (NautilusProgressInfo *info) +queue_idle (NautilusProgressInfo *info, gboolean now) { - if (info->idle_tag != 0) - info->idle_tag = g_idle_add (idle_callback, g_object_ref (info)); + if (info->idle_source == NULL || + (now && !info->source_is_now)) { + if (info->idle_source) { + g_source_destroy (info->idle_source); + g_source_unref (info->idle_source); + info->idle_source = NULL; + } + + info->source_is_now = now; + if (now) { + info->idle_source = g_idle_source_new (); + } else { + info->idle_source = g_timeout_source_new (SIGNAL_DELAY_MSEC); + } + g_source_set_callback (info->idle_source, idle_callback, info, NULL); + g_source_attach (info->idle_source, NULL); + } } void nautilus_progress_info_start (NautilusProgressInfo *info) { - G_LOCK (progress_info); - - if (!info->started) - { - info->started = TRUE; - - info->start_at_idle = TRUE; - queue_idle (info); - } - - G_UNLOCK (progress_info); + G_LOCK (progress_info); + + if (!info->started) { + info->started = TRUE; + + info->start_at_idle = TRUE; + queue_idle (info, TRUE); + } + + G_UNLOCK (progress_info); } void nautilus_progress_info_finish (NautilusProgressInfo *info) { - G_LOCK (progress_info); - - if (!info->finished) - { - info->finished = TRUE; - - info->finish_at_idle = TRUE; - queue_idle (info); - } - - G_UNLOCK (progress_info); + G_LOCK (progress_info); + + if (!info->finished) { + info->finished = TRUE; + + info->finish_at_idle = TRUE; + queue_idle (info, TRUE); + } + + G_UNLOCK (progress_info); } void nautilus_progress_info_set_status (NautilusProgressInfo *info, const char *status) { - G_LOCK (progress_info); - - if (eel_strcmp (info->status, status) != 0) - { - g_free (info->status); - info->status = g_strdup (status); - - info->changed_at_idle = TRUE; - queue_idle (info); - } - - G_UNLOCK (progress_info); + G_LOCK (progress_info); + + if (eel_strcmp (info->status, status) != 0) { + g_free (info->status); + info->status = g_strdup (status); + + info->changed_at_idle = TRUE; + queue_idle (info, FALSE); + } + + G_UNLOCK (progress_info); } void nautilus_progress_info_set_details (NautilusProgressInfo *info, const char *details) { - G_LOCK (progress_info); - - if (eel_strcmp (info->details, details) != 0) - { - g_free (info->details); - info->details = g_strdup (details); - - info->changed_at_idle = TRUE; - queue_idle (info); - } - - G_UNLOCK (progress_info); + G_LOCK (progress_info); + + if (eel_strcmp (info->details, details) != 0) { + g_free (info->details); + info->details = g_strdup (details); + + info->changed_at_idle = TRUE; + queue_idle (info, FALSE); + } + + G_UNLOCK (progress_info); } void @@ -369,18 +429,17 @@ nautilus_progress_info_set_progress (NautilusProgressInfo *info, gboolean activity_mode, double current_percent) { - G_LOCK (progress_info); - - if (activity_mode || /* Always pulse if activity mode */ - info->activity_mode || /* emit on switch from activity mode */ - fabs (current_percent - info->progress) > 0.1 /* Emit on change of 0.1 percent */ - ) - { - info->progress = current_percent; - - info->progress_at_idle = TRUE; - queue_idle (info); - } - - G_UNLOCK (progress_info); + G_LOCK (progress_info); + + if (activity_mode || /* Always pulse if activity mode */ + info->activity_mode || /* emit on switch from activity mode */ + fabs (current_percent - info->progress) > 0.1 /* Emit on change of 0.1 percent */ + ) { + info->progress = current_percent; + + info->progress_at_idle = TRUE; + queue_idle (info, FALSE); + } + + G_UNLOCK (progress_info); } |