summaryrefslogtreecommitdiff
path: root/libebackend/e-source-registry-server.c
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2015-07-03 08:03:50 +0200
committerMilan Crha <mcrha@redhat.com>2015-07-03 08:03:50 +0200
commit5736bd56c60796237972dc56e97c7b46efa362bb (patch)
tree170bd4b85e3b5809b3f988fa7fbeca1c9d687d46 /libebackend/e-source-registry-server.c
parentec979f813796a53d0ac5f0c4867ecc54505babe2 (diff)
downloadevolution-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.c191
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",