summaryrefslogtreecommitdiff
path: root/gtk/gtkrecentmanager.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@linux.intel.com>2010-10-22 16:12:16 +0100
committerEmmanuele Bassi <ebassi@linux.intel.com>2010-10-22 18:08:48 +0100
commitce5a29bc384542839a5f12061499c8ec706b1c34 (patch)
tree68f193cd5169f1e07a02a15c1ff9af4d027fbf71 /gtk/gtkrecentmanager.c
parent5ef2b46d64ebf0a460e92f60e7386a46c3540c9d (diff)
downloadgtk+-ce5a29bc384542839a5f12061499c8ec706b1c34.tar.gz
recent-manager: Coalesce multiple changes
Since the ::changed implementation of GtkRecentManager implies a synchronous write operation, when we receive multiple requests to emit a ::changed signal we might end up blocking. This change coalesces multiple ::changed emission requests using the following sequence: • the first request will install a timeout in 250 ms, which will emit the ::changed signal • each further request while the timeout has not been emitted will increase a counter ‣ if the counter reaches 250 before the timeout has been emitted, then the RecentManager will remove the timeout source and force a signal emission and reset the counter This sequence should guarantee that frequent ::changed emission requests are coalesced, and also guarantee that we don't let them dangle for too long. https://bugzilla.gnome.org/show_bug.cgi?id=616997
Diffstat (limited to 'gtk/gtkrecentmanager.c')
-rw-r--r--gtk/gtkrecentmanager.c99
1 files changed, 71 insertions, 28 deletions
diff --git a/gtk/gtkrecentmanager.c b/gtk/gtkrecentmanager.c
index 9730172ba9..ccdea45310 100644
--- a/gtk/gtkrecentmanager.c
+++ b/gtk/gtkrecentmanager.c
@@ -176,6 +176,9 @@ struct _GtkRecentManagerPrivate
GBookmarkFile *recent_items;
GFileMonitor *monitor;
+
+ guint changed_timeout;
+ guint changed_age;
};
enum
@@ -390,12 +393,26 @@ gtk_recent_manager_get_property (GObject *object,
}
static void
-gtk_recent_manager_dispose (GObject *object)
+gtk_recent_manager_finalize (GObject *object)
{
GtkRecentManager *manager = GTK_RECENT_MANAGER (object);
GtkRecentManagerPrivate *priv = manager->priv;
- if (priv->monitor)
+ g_free (priv->filename);
+
+ if (priv->recent_items != NULL)
+ g_bookmark_file_free (priv->recent_items);
+
+ G_OBJECT_CLASS (gtk_recent_manager_parent_class)->finalize (object);
+}
+
+static void
+gtk_recent_manager_dispose (GObject *gobject)
+{
+ GtkRecentManager *manager = GTK_RECENT_MANAGER (gobject);
+ GtkRecentManagerPrivate *priv = manager->priv;
+
+ if (priv->monitor != NULL)
{
g_signal_handlers_disconnect_by_func (priv->monitor,
G_CALLBACK (gtk_recent_manager_monitor_changed),
@@ -404,21 +421,21 @@ gtk_recent_manager_dispose (GObject *object)
priv->monitor = NULL;
}
- G_OBJECT_CLASS (gtk_recent_manager_parent_class)->dispose (object);
-}
-
-static void
-gtk_recent_manager_finalize (GObject *object)
-{
- GtkRecentManager *manager = GTK_RECENT_MANAGER (object);
- GtkRecentManagerPrivate *priv = manager->priv;
+ if (priv->changed_timeout != 0)
+ {
+ g_source_remove (priv->changed_timeout);
+ priv->changed_timeout = 0;
+ priv->changed_age = 0;
+ }
- g_free (priv->filename);
-
- if (priv->recent_items)
- g_bookmark_file_free (priv->recent_items);
+ if (priv->is_dirty)
+ {
+ g_object_ref (manager);
+ g_signal_emit (manager, signal_changed, 0);
+ g_object_unref (manager);
+ }
- G_OBJECT_CLASS (gtk_recent_manager_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gtk_recent_manager_parent_class)->dispose (gobject);
}
static void
@@ -456,8 +473,6 @@ gtk_recent_manager_real_changed (GtkRecentManager *manager)
else if (age == 0)
{
g_bookmark_file_free (priv->recent_items);
- priv->recent_items = NULL;
-
priv->recent_items = g_bookmark_file_new ();
}
}
@@ -942,7 +957,6 @@ gtk_recent_manager_add_full (GtkRecentManager *manager,
* will dump our changes
*/
priv->is_dirty = TRUE;
-
gtk_recent_manager_changed (manager);
return TRUE;
@@ -1003,7 +1017,6 @@ gtk_recent_manager_remove_item (GtkRecentManager *manager,
}
priv->is_dirty = TRUE;
-
gtk_recent_manager_changed (manager);
return TRUE;
@@ -1227,7 +1240,6 @@ gtk_recent_manager_move_item (GtkRecentManager *recent_manager,
}
priv->is_dirty = TRUE;
-
gtk_recent_manager_changed (recent_manager);
return TRUE;
@@ -1282,17 +1294,15 @@ purge_recent_items_list (GtkRecentManager *manager,
{
GtkRecentManagerPrivate *priv = manager->priv;
- if (!priv->recent_items)
+ if (priv->recent_items == NULL)
return;
-
+
g_bookmark_file_free (priv->recent_items);
- priv->recent_items = NULL;
-
priv->recent_items = g_bookmark_file_new ();
priv->size = 0;
- priv->is_dirty = TRUE;
-
+
/* emit the changed signal, to ensure that the purge is written */
+ priv->is_dirty = TRUE;
gtk_recent_manager_changed (manager);
}
@@ -1332,10 +1342,43 @@ gtk_recent_manager_purge_items (GtkRecentManager *manager,
return purged;
}
+static gboolean
+emit_manager_changed (gpointer data)
+{
+ GtkRecentManager *manager = data;
+
+ manager->priv->changed_age = 0;
+ manager->priv->changed_timeout = 0;
+
+ g_signal_emit (manager, signal_changed, 0);
+
+ return FALSE;
+}
+
static void
-gtk_recent_manager_changed (GtkRecentManager *recent_manager)
+gtk_recent_manager_changed (GtkRecentManager *manager)
{
- g_signal_emit (recent_manager, signal_changed, 0);
+ /* coalesce consecutive changes
+ *
+ * we schedule a write in 250 msecs immediately; if we get more than one
+ * request per millisecond before the timeout has a chance to run, we
+ * schedule an emission immediately.
+ */
+ if (manager->priv->changed_timeout == 0)
+ manager->priv->changed_timeout = gdk_threads_add_timeout (250, emit_manager_changed, manager);
+ else
+ {
+ manager->priv->changed_age += 1;
+
+ if (manager->priv->changed_age > 250)
+ {
+ g_source_remove (manager->priv->changed_timeout);
+ g_signal_emit (manager, signal_changed, 0);
+
+ manager->priv->changed_age = 0;
+ manager->priv->changed_timeout = 0;
+ }
+ }
}
static void