diff options
| author | Tristan Van Berkom <tristanvb@openismus.com> | 2013-11-30 01:19:04 +0900 |
|---|---|---|
| committer | Tristan Van Berkom <tristanvb@openismus.com> | 2013-11-30 03:36:29 +0900 |
| commit | c8914fc768a69360cef64a65424e05a2f39d25b3 (patch) | |
| tree | bcf66da9c6eb5136ead79c6bf63329ccf3784b9d /addressbook | |
| parent | 67b446aacd1d85e3ebcdcf5dafc3932076174c79 (diff) | |
| download | evolution-data-server-c8914fc768a69360cef64a65424e05a2f39d25b3.tar.gz | |
EDataBookFactor / EDataBook: Migrated locale handling to EDataBookFactory
The EDataBookFactory is the server side singleton, this is the right
place to handle locale changes, now each EDataBook is set into the
correct locale by the factory, when books are created, and when the
locale change notification arrives.
Diffstat (limited to 'addressbook')
| -rw-r--r-- | addressbook/libedata-book/e-data-book-cursor.c | 1 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-data-book-factory.c | 250 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-data-book.c | 227 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-data-book.h | 5 |
4 files changed, 294 insertions, 189 deletions
diff --git a/addressbook/libedata-book/e-data-book-cursor.c b/addressbook/libedata-book/e-data-book-cursor.c index 6e44c1d1a..341aa48d9 100644 --- a/addressbook/libedata-book/e-data-book-cursor.c +++ b/addressbook/libedata-book/e-data-book-cursor.c @@ -667,6 +667,7 @@ data_book_cursor_handle_dispose (EDBusAddressBookCursor *dbus_object, g_warning ("Error trying to delete cursor: %s", error->message); g_clear_error (&error); } + e_dbus_address_book_cursor_complete_dispose (dbus_object, invocation); g_object_unref (cursor); diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c index 7017aa14c..6e0611601 100644 --- a/addressbook/libedata-book/e-data-book-factory.c +++ b/addressbook/libedata-book/e-data-book-factory.c @@ -33,6 +33,7 @@ #include "e-book-backend-factory.h" #include "e-data-book.h" #include "e-data-book-factory.h" +#include "e-dbus-localed.h" #define d(x) @@ -53,6 +54,12 @@ struct _EDataBookFactoryPrivate { * The value is the watcher ID for g_bus_unwatch_name(). */ GHashTable *watched_names; GMutex watched_names_lock; + + /* Watching "org.freedesktop.locale1" for locale changes */ + guint localed_watch_id; + EDBusLocale1 *localed_proxy; + GCancellable *localed_cancel; + gchar *locale; }; enum { @@ -304,6 +311,43 @@ data_book_factory_closed_cb (EBookBackend *backend, data_book_factory_connections_remove (factory, sender, backend); } +/* This is totally backwards, for some insane reason we holding + * references to the EBookBackends and then fetching the EDataBook + * via e_book_backend_ref_data_book(), the whole scheme should + * be reversed and this function probably removed. + */ +static GList * +data_book_factory_list_books (EDataBookFactory *factory) +{ + GList *books = NULL; + GHashTable *connections; + GHashTableIter iter; + gpointer key, value; + + g_mutex_lock (&factory->priv->connections_lock); + + connections = factory->priv->connections; + + g_hash_table_iter_init (&iter, connections); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GPtrArray *array = (GPtrArray *)value; + gint i; + + for (i = 0; i < array->len; i++) { + EBookBackend *backend = g_ptr_array_index (array, i); + EDataBook *book = e_book_backend_ref_data_book (backend); + + if (g_list_find (books, book) == NULL) + books = g_list_prepend (books, book); + else + g_object_unref (book); + } + } + g_mutex_unlock (&factory->priv->connections_lock); + + return books; +} + static gchar * data_book_factory_open (EDataBookFactory *factory, GDBusConnection *connection, @@ -375,6 +419,13 @@ data_book_factory_open (EDataBookFactory *factory, G_CALLBACK (data_book_factory_closed_cb), factory, 0); + /* Don't set the locale on a new book if we have not + * yet received a notification of a locale change + */ + if (factory->priv->locale) + e_data_book_set_locale (data_book, + factory->priv->locale, + NULL, NULL); } else { g_free (object_path); object_path = NULL; @@ -464,6 +515,20 @@ data_book_factory_dispose (GObject *object) priv->dbus_factory = NULL; } + if (priv->localed_cancel) { + g_cancellable_cancel (priv->localed_cancel); + g_object_unref (priv->localed_cancel); + priv->localed_cancel = NULL; + } + + if (priv->localed_proxy) { + g_object_unref (priv->localed_proxy); + priv->localed_proxy = NULL; + } + + if (priv->localed_watch_id > 0) + g_bus_unwatch_name (priv->localed_watch_id); + g_hash_table_remove_all (priv->connections); g_hash_table_remove_all (priv->watched_names); @@ -484,6 +549,8 @@ data_book_factory_finalize (GObject *object) g_hash_table_destroy (priv->watched_names); g_mutex_clear (&priv->watched_names_lock); + g_free (priv->locale); + /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize (object); } @@ -546,17 +613,200 @@ data_book_factory_quit_server (EDBusServer *server, quit_server (server, exit_code); } +static gchar * +data_book_factory_interpret_locale_value (const gchar *value) +{ + gchar *interpreted_value = NULL; + gchar **split; + + split = g_strsplit (value, "=", 2); + + if (split && split[0] && split[1]) + interpreted_value = g_strdup (split[1]); + + g_strfreev (split); + + if (!interpreted_value) + g_warning ("Failed to interpret locale value: %s", value); + + return interpreted_value; +} + +static gchar * +data_book_factory_interpret_locale (const gchar * const * locale) +{ + gint i; + gchar *interpreted_locale = NULL; + + /* Prioritize LC_COLLATE and then LANG values + * in the 'locale' specified by localed. + * + * If localed explicitly specifies no locale, then + * default to checking system locale. + */ + if (locale) { + for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) { + if (strncmp (locale[i], "LC_COLLATE", 10) == 0) + interpreted_locale = + data_book_factory_interpret_locale_value (locale[i]); + } + + for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) { + if (strncmp (locale[i], "LANG", 4) == 0) + interpreted_locale = + data_book_factory_interpret_locale_value (locale[i]); + } + } + + if (!interpreted_locale) { + const gchar *system_locale = setlocale (LC_COLLATE, NULL); + + interpreted_locale = g_strdup (system_locale); + } + + return interpreted_locale; +} + +static void +data_book_factory_set_locale (EDataBookFactory *factory, + const gchar *locale) +{ + EDataBookFactoryPrivate *priv = factory->priv; + GError *error = NULL; + GList *books, *l; + + if (g_strcmp0 (priv->locale, locale) != 0) { + + g_free (priv->locale); + priv->locale = g_strdup (locale); + + books = data_book_factory_list_books (factory); + for (l = books; l; l = l->next) { + EDataBook *book = l->data; + + if (!e_data_book_set_locale (book, locale, NULL, &error)) { + g_warning ("Failed to set locale on addressbook: %s", + error->message); + g_clear_error (&error); + } + } + g_list_free_full (books, g_object_unref); + } +} + +static void +data_book_factory_locale_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object); + EDataBookFactory *factory = (EDataBookFactory *)user_data; + const gchar * const *locale; + gchar *interpreted_locale; + + locale = e_dbus_locale1_get_locale (locale_proxy); + interpreted_locale = data_book_factory_interpret_locale (locale); + + data_book_factory_set_locale (factory, interpreted_locale); + + g_free (interpreted_locale); +} + +static void +data_book_factory_localed_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EDataBookFactory *factory = (EDataBookFactory *)user_data; + GError *error = NULL; + + factory->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error); + + if (factory->priv->localed_proxy == NULL) { + g_warning ("Error fetching localed proxy: %s", error->message); + g_error_free (error); + } + + if (factory->priv->localed_cancel) { + g_object_unref (factory->priv->localed_cancel); + factory->priv->localed_cancel = NULL; + } + + if (factory->priv->localed_proxy) { + g_signal_connect (factory->priv->localed_proxy, "notify::locale", + G_CALLBACK (data_book_factory_locale_changed), factory); + + /* Initial refresh of the locale */ + data_book_factory_locale_changed (G_OBJECT (factory->priv->localed_proxy), NULL, factory); + } +} + +static void +data_book_factory_localed_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + EDataBookFactory *factory = (EDataBookFactory *)user_data; + + factory->priv->localed_cancel = g_cancellable_new (); + + e_dbus_locale1_proxy_new (connection, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + factory->priv->localed_cancel, + data_book_factory_localed_ready, + factory); +} + +static void +data_book_factory_localed_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + EDataBookFactory *factory = (EDataBookFactory *)user_data; + + if (factory->priv->localed_cancel) { + g_cancellable_cancel (factory->priv->localed_cancel); + g_object_unref (factory->priv->localed_cancel); + factory->priv->localed_cancel = NULL; + } + + if (factory->priv->localed_proxy) { + g_object_unref (factory->priv->localed_proxy); + factory->priv->localed_proxy = NULL; + } +} + static gboolean data_book_factory_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { EDataBookFactoryPrivate *priv; + GBusType bus_type = G_BUS_TYPE_SYSTEM; priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (initable); priv->registry = e_source_registry_new_sync (cancellable, error); + /* When running tests, we pretend to be the "org.freedesktop.locale1" service + * on the session bus instead of the real location on the system bus. + */ + if (g_getenv ("EDS_TESTING") != NULL) + bus_type = G_BUS_TYPE_SESSION; + + /* Watch system bus for locale change notifications */ + priv->localed_watch_id = + g_bus_watch_name (bus_type, + "org.freedesktop.locale1", + G_BUS_NAME_WATCHER_FLAGS_NONE, + data_book_factory_localed_appeared, + data_book_factory_localed_vanished, + initable, + NULL); + return (priv->registry != NULL); } diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c index 935b1f53e..97b04b223 100644 --- a/addressbook/libedata-book/e-data-book.c +++ b/addressbook/libedata-book/e-data-book.c @@ -37,7 +37,6 @@ #include "e-book-backend.h" #include "e-book-backend-sexp.h" #include "e-book-backend-factory.h" -#include "e-dbus-localed.h" #define E_DATA_BOOK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -56,10 +55,6 @@ struct _EDataBookPrivate { GMutex sender_lock; GHashTable *sender_table; - - guint localed_watch_id; - EDBusLocale1 *localed_proxy; - GCancellable *localed_cancel; }; struct _AsyncContext { @@ -1644,159 +1639,6 @@ e_data_book_report_backend_property_changed (EDataBook *book, /* Disregard anything else. */ } -static gchar * -data_book_interpret_locale_value (const gchar *value) -{ - gchar *interpreted_value = NULL; - gchar **split; - - split = g_strsplit (value, "=", 2); - - if (split && split[0] && split[1]) - interpreted_value = g_strdup (split[1]); - - g_strfreev (split); - - if (!interpreted_value) - g_warning ("Failed to interpret locale value: %s", value); - - return interpreted_value; -} - -static gchar * -data_book_interpret_locale (const gchar * const * locale) -{ - gint i; - gchar *interpreted_locale = NULL; - - /* Prioritize LC_COLLATE and then LANG values - * in the 'locale' specified by localed. - * - * If localed explicitly specifies no locale, then - * default to checking system locale. - */ - if (locale) { - - for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) { - - if (strncmp (locale[i], "LC_COLLATE", 10) == 0) - interpreted_locale = data_book_interpret_locale_value (locale[i]); - } - - for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) { - - if (strncmp (locale[i], "LANG", 4) == 0) - interpreted_locale = data_book_interpret_locale_value (locale[i]); - } - } - - if (!interpreted_locale) { - const gchar *system_locale = setlocale (LC_COLLATE, NULL); - - interpreted_locale = g_strdup (system_locale); - } - - return interpreted_locale; -} - -static void -data_book_locale_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object); - EDataBook *book = (EDataBook *)user_data; - EBookBackend *backend; - - backend = e_data_book_ref_backend (book); - - if (backend) { - const gchar * const *locale; - gchar *interpreted_locale; - - locale = e_dbus_locale1_get_locale (locale_proxy); - interpreted_locale = data_book_interpret_locale (locale); - - /* XXX This needs work, the whole handling should be done - * by the singleton EDataBookFactory, and handle errors well - */ - e_book_backend_set_locale (backend, interpreted_locale, NULL, NULL); - - e_dbus_address_book_set_locale (book->priv->dbus_interface, interpreted_locale); - - g_free (interpreted_locale); - } - - g_object_unref (backend); -} - -static void -data_book_localed_ready (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - EDataBook *book = (EDataBook *)user_data; - GError *error = NULL; - - book->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error); - - if (book->priv->localed_proxy == NULL) { - g_warning ("Error fetching localed proxy: %s", error->message); - g_error_free (error); - } - - if (book->priv->localed_cancel) { - g_object_unref (book->priv->localed_cancel); - book->priv->localed_cancel = NULL; - } - - if (book->priv->localed_proxy) { - g_signal_connect (book->priv->localed_proxy, "notify::locale", - G_CALLBACK (data_book_locale_changed), book); - - /* Initial refresh of the locale */ - data_book_locale_changed (G_OBJECT (book->priv->localed_proxy), NULL, book); - } -} - -static void -data_book_localed_appeared (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - EDataBook *book = (EDataBook *)user_data; - - book->priv->localed_cancel = g_cancellable_new (); - - e_dbus_locale1_proxy_new (connection, - G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - book->priv->localed_cancel, - data_book_localed_ready, - book); -} - -static void -data_book_localed_vanished (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - EDataBook *book = (EDataBook *)user_data; - - if (book->priv->localed_cancel) { - g_cancellable_cancel (book->priv->localed_cancel); - g_object_unref (book->priv->localed_cancel); - book->priv->localed_cancel = NULL; - } - - if (book->priv->localed_proxy) { - g_object_unref (book->priv->localed_proxy); - book->priv->localed_proxy = NULL; - } -} - static void data_book_set_backend (EDataBook *book, EBookBackend *backend) @@ -1912,17 +1754,6 @@ data_book_dispose (GObject *object) priv->direct_module = NULL; } - if (priv->localed_cancel) { - g_cancellable_cancel (priv->localed_cancel); - g_object_unref (priv->localed_cancel); - priv->localed_cancel = NULL; - } - - if (priv->localed_proxy) { - g_object_unref (priv->localed_proxy); - priv->localed_proxy = NULL; - } - g_hash_table_remove_all (priv->sender_table); /* Chain up to parent's dispose() metnod. */ @@ -1946,9 +1777,6 @@ data_book_finalize (GObject *object) priv->dbus_interface = NULL; } - if (priv->localed_watch_id > 0) - g_bus_unwatch_name (priv->localed_watch_id); - /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object); } @@ -2028,7 +1856,6 @@ data_book_initable_init (GInitable *initable, EBookBackend *backend; EDataBook *book; gchar *locale; - GBusType bus_type = G_BUS_TYPE_SYSTEM; book = E_DATA_BOOK (initable); @@ -2065,22 +1892,6 @@ data_book_initable_init (GInitable *initable, e_dbus_address_book_set_locale (book->priv->dbus_interface, locale); g_free (locale); - /* When running tests, we pretend to be the "org.freedesktop.locale1" service - * on the session bus instead of the real location on the system bus. - */ - if (g_getenv ("EDS_TESTING") != NULL) - bus_type = G_BUS_TYPE_SESSION; - - /* Watch system bus for locale change notifications */ - book->priv->localed_watch_id = - g_bus_watch_name (bus_type, - "org.freedesktop.locale1", - G_BUS_NAME_WATCHER_FLAGS_NONE, - data_book_localed_appeared, - data_book_localed_vanished, - book, - NULL); - return g_dbus_interface_skeleton_export ( G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface), book->priv->connection, @@ -2303,3 +2114,41 @@ e_data_book_get_object_path (EDataBook *book) return book->priv->object_path; } +/** + * e_data_book_set_locale: + * @book: an #EDataBook + * @locale: the new locale to set for this book + * @cancellable: (allow-none): a #GCancellable + * @error: (allow-none): a location to store any error which might occur + * + * Set's the locale for this addressbook, this can result in renormalization of + * locale sensitive data. + * + * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately. + * + * Since: 3.12 + */ +gboolean +e_data_book_set_locale (EDataBook *book, + const gchar *locale, + GCancellable *cancellable, + GError **error) +{ + EBookBackend *backend; + gboolean success; + + g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE); + + backend = e_data_book_ref_backend (book); + success = e_book_backend_set_locale (backend, + locale, + cancellable, + error); + + if (success) + e_dbus_address_book_set_locale (book->priv->dbus_interface, locale); + + g_object_unref (backend); + + return success; +} diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h index d3bc9a246..e7d09492e 100644 --- a/addressbook/libedata-book/e-data-book.h +++ b/addressbook/libedata-book/e-data-book.h @@ -106,6 +106,10 @@ GDBusConnection * e_data_book_get_connection (EDataBook *book); const gchar * e_data_book_get_object_path (EDataBook *book); +gboolean e_data_book_set_locale (EDataBook *book, + const gchar *locale, + GCancellable *cancellable, + GError **error); void e_data_book_respond_open (EDataBook *book, guint32 opid, GError *error); @@ -152,6 +156,7 @@ void e_data_book_report_backend_property_changed gchar * e_data_book_string_slist_to_comma_string (const GSList *strings); + G_END_DECLS #endif /* E_DATA_BOOK_H */ |
