diff options
author | Milan Crha <mcrha@redhat.com> | 2015-07-03 08:03:50 +0200 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2015-07-03 08:03:50 +0200 |
commit | 5736bd56c60796237972dc56e97c7b46efa362bb (patch) | |
tree | 170bd4b85e3b5809b3f988fa7fbeca1c9d687d46 /libebackend/e-source-registry-server.c | |
parent | ec979f813796a53d0ac5f0c4867ecc54505babe2 (diff) | |
download | evolution-data-server-5736bd56c60796237972dc56e97c7b46efa362bb.tar.gz |
Bug 751657 - ESource can be removed after its property change
Diffstat (limited to 'libebackend/e-source-registry-server.c')
-rw-r--r-- | libebackend/e-source-registry-server.c | 191 |
1 files changed, 148 insertions, 43 deletions
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c index 9f64b5061..7d34c660b 100644 --- a/libebackend/e-source-registry-server.c +++ b/libebackend/e-source-registry-server.c @@ -66,6 +66,10 @@ struct _ESourceRegistryServerPrivate { GMutex orphans_lock; ESourceCredentialsProvider *credentials_provider; + + GMutex file_monitor_lock; + GHashTable *file_monitor_events; /* gchar *uid ~> FileEventData * */ + GSource *file_monitor_source; }; enum { @@ -414,18 +418,52 @@ source_registry_server_reload_cb (EDBusSourceManager *dbus_interface, return TRUE; } +typedef struct _FileEventData { + GFile *file; + GFileMonitorEvent event_type; +} FileEventData; + +static FileEventData * +file_event_data_new (GFile *file, + GFileMonitorEvent event_type) +{ + FileEventData *fed; + + fed = g_new0 (FileEventData, 1); + fed->file = g_object_ref (file); + fed->event_type = event_type; + + return fed; +} + static void -source_registry_server_monitor_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - ESourceRegistryServer *server) +file_event_data_free (gpointer ptr) { - gchar *uri; + FileEventData *fed = ptr; + + if (fed) { + g_clear_object (&fed->file); + g_free (fed); + } +} + +static void +source_registry_server_process_file_monitor_event (gpointer key, + gpointer value, + gpointer user_data) +{ + const gchar *uid = key; + const FileEventData *fed = value; + ESourceRegistryServer *server = user_data; + GFileMonitorEvent event_type; + + g_return_if_fail (uid != NULL); + g_return_if_fail (fed != NULL); + + event_type = fed->event_type; if (e_source_registry_debug_enabled ()) { - uri = g_file_get_uri (file); - e_source_registry_debug_print ("Handling file monitor event %s (%u) for URI: %s\n", + e_source_registry_debug_print ("Processing file monitor event %s (%u) for UID: %s\n", event_type == G_FILE_MONITOR_EVENT_CHANGED ? "CHANGED" : event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT ? "CHANGES_DONE_HINT" : event_type == G_FILE_MONITOR_EVENT_DELETED ? "DELETED" : @@ -435,25 +473,16 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor, event_type == G_FILE_MONITOR_EVENT_UNMOUNTED ? "UNMOUNTED" : event_type == G_FILE_MONITOR_EVENT_MOVED ? "MOVED" : "???", event_type, - uri); - g_free (uri); + uid); } if (event_type == G_FILE_MONITOR_EVENT_CHANGED || event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) { ESource *source; - gchar *uid; GError *error = NULL; - uid = e_server_side_source_uid_from_file (file, NULL); - - if (uid == NULL) - return; - source = e_source_registry_server_ref_source (server, uid); - g_free (uid); - /* If the source does not exist, create it; parsing may have * failed when the file was originally created. This can happen * if the file is created (empty), then e-source-registry-server @@ -463,10 +492,8 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor, if (source == NULL) { event_type = G_FILE_MONITOR_EVENT_CREATED; } else if (!e_server_side_source_load (E_SERVER_SIDE_SOURCE (source), NULL, &error)) { - uri = g_file_get_uri (file); - g_warning ("Error reloading source ā%sā: %s", uri, error->message); + g_warning ("Error reloading source ā%sā: %s", uid, error->message); - g_free (uri); g_error_free (error); g_object_unref (source); @@ -479,34 +506,24 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor, if (event_type == G_FILE_MONITOR_EVENT_CREATED) { ESource *source; GError *error = NULL; - gchar *uid; - - uid = e_server_side_source_uid_from_file (file, NULL); - if (!uid) - return; source = e_source_registry_server_ref_source (server, uid); - g_free (uid); - if (!source) { /* it can return NULL source for hidden files */ - source = e_server_side_source_new (server, file, &error); + source = e_server_side_source_new (server, fed->file, &error); } if (!error && source) { /* File monitors are only placed on directories * where data sources are writable and removable, * so it should be safe to assume these flags. */ - e_server_side_source_set_writable ( - E_SERVER_SIDE_SOURCE (source), TRUE); - e_server_side_source_set_removable ( - E_SERVER_SIDE_SOURCE (source), TRUE); + e_server_side_source_set_writable (E_SERVER_SIDE_SOURCE (source), TRUE); + e_server_side_source_set_removable (E_SERVER_SIDE_SOURCE (source), TRUE); e_source_registry_server_add_source (server, source); } else if (error) { - e_source_registry_server_load_error ( - server, file, error); + e_source_registry_server_load_error (server, fed->file, error); g_error_free (error); } @@ -515,17 +532,9 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor, if (event_type == G_FILE_MONITOR_EVENT_DELETED) { ESource *source; - gchar *uid; - - uid = e_server_side_source_uid_from_file (file, NULL); - - if (uid == NULL) - return; source = e_source_registry_server_ref_source (server, uid); - g_free (uid); - if (source == NULL) return; @@ -540,6 +549,87 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor, } static gboolean +source_registry_server_process_file_monitor_events_cb (gpointer user_data) +{ + ESourceRegistryServer *server = user_data; + GHashTable *events; + + if (g_source_is_destroyed (g_main_current_source ())) + return FALSE; + + g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), FALSE); + + g_mutex_lock (&server->priv->file_monitor_lock); + events = server->priv->file_monitor_events; + server->priv->file_monitor_events = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, file_event_data_free); + g_mutex_unlock (&server->priv->file_monitor_lock); + + g_hash_table_foreach (events, source_registry_server_process_file_monitor_event, server); + g_hash_table_destroy (events); + + return FALSE; +} + +static void +source_registry_server_monitor_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + ESourceRegistryServer *server) +{ + if (e_source_registry_debug_enabled ()) { + gchar *uri; + + uri = g_file_get_uri (file); + e_source_registry_debug_print ("Handling file monitor event %s (%u) for URI: %s\n", + event_type == G_FILE_MONITOR_EVENT_CHANGED ? "CHANGED" : + event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT ? "CHANGES_DONE_HINT" : + event_type == G_FILE_MONITOR_EVENT_DELETED ? "DELETED" : + event_type == G_FILE_MONITOR_EVENT_CREATED ? "CREATED" : + event_type == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED ? "ATTRIBUTE_CHANGED" : + event_type == G_FILE_MONITOR_EVENT_PRE_UNMOUNT ? "PRE_UNMOUNT" : + event_type == G_FILE_MONITOR_EVENT_UNMOUNTED ? "UNMOUNTED" : + event_type == G_FILE_MONITOR_EVENT_MOVED ? "MOVED" : "???", + event_type, + uri); + g_free (uri); + } + + if (event_type == G_FILE_MONITOR_EVENT_CHANGED || + event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT || + event_type == G_FILE_MONITOR_EVENT_CREATED || + event_type == G_FILE_MONITOR_EVENT_DELETED) { + gchar *uid; + + uid = e_server_side_source_uid_from_file (file, NULL); + + if (uid == NULL) + return; + + g_mutex_lock (&server->priv->file_monitor_lock); + /* This overwrites any previous events, aka the last wins + (overwrite can be DELETE + CREATE, which handles it correctly). */ + g_hash_table_insert (server->priv->file_monitor_events, uid, file_event_data_new (file, event_type)); + + if (server->priv->file_monitor_source) { + g_source_destroy (server->priv->file_monitor_source); + g_source_unref (server->priv->file_monitor_source); + } + + server->priv->file_monitor_source = g_timeout_source_new_seconds (3); + g_source_set_callback ( + server->priv->file_monitor_source, + source_registry_server_process_file_monitor_events_cb, + server, NULL); + g_source_attach ( + server->priv->file_monitor_source, + server->priv->main_context); + + g_mutex_unlock (&server->priv->file_monitor_lock); + } +} + +static gboolean source_registry_server_traverse_cb (GNode *node, GQueue *queue) { @@ -642,6 +732,14 @@ source_registry_server_dispose (GObject *object) priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (object); + g_mutex_lock (&priv->file_monitor_lock); + if (priv->file_monitor_source) { + g_source_destroy (priv->file_monitor_source); + g_source_unref (priv->file_monitor_source); + priv->file_monitor_source = NULL; + } + g_mutex_unlock (&priv->file_monitor_lock); + if (priv->main_context != NULL) { g_main_context_unref (priv->main_context); priv->main_context = NULL; @@ -654,6 +752,7 @@ source_registry_server_dispose (GObject *object) g_hash_table_remove_all (priv->sources); g_hash_table_remove_all (priv->orphans); g_hash_table_remove_all (priv->monitors); + g_hash_table_remove_all (priv->file_monitor_events); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_source_registry_server_parent_class)-> @@ -670,9 +769,11 @@ source_registry_server_finalize (GObject *object) g_hash_table_destroy (priv->sources); g_hash_table_destroy (priv->orphans); g_hash_table_destroy (priv->monitors); + g_hash_table_destroy (priv->file_monitor_events); g_mutex_clear (&priv->sources_lock); g_mutex_clear (&priv->orphans_lock); + g_mutex_clear (&priv->file_monitor_lock); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_source_registry_server_parent_class)-> @@ -1021,6 +1122,10 @@ e_source_registry_server_init (ESourceRegistryServer *server) server->priv->monitors = monitors; g_mutex_init (&server->priv->sources_lock); g_mutex_init (&server->priv->orphans_lock); + g_mutex_init (&server->priv->file_monitor_lock); + + server->priv->file_monitor_source = NULL; + server->priv->file_monitor_events = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, file_event_data_free); g_signal_connect ( source_manager, "handle-create-sources", |