summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2007-11-16 12:55:14 +0000
committerAlexander Larsson <alexl@src.gnome.org>2007-11-16 12:55:14 +0000
commitb5575ad4fd357c4e2e97166adb163c5d95ea7bbe (patch)
treebe27794af6f4fce1ebe63e39aebc62736a742171
parent144c3c5f701650cf9ddeff8de9431155954a48df (diff)
downloadnautilus-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--ChangeLog6
-rw-r--r--libnautilus-private/nautilus-progress-info.c547
2 files changed, 309 insertions, 244 deletions
diff --git a/ChangeLog b/ChangeLog
index 3db49f191..f537ef8cc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
}