[evolution-data-server/openismus-work] EDataBook: Watch the system bus for locale notifications



commit 148a301bbc880d50db8c90674816c3da5f0892be
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Thu May 23 15:24:09 2013 +0900

    EDataBook: Watch the system bus for locale notifications
    
    When org.freedesktop.locale1 is available, listen to changes in
    the LC_COLLATE locale and configure backends with locale changes
    using e_book_backend_set_locale(), notify property changes via
    the locale property on the addressbook D-Bus API.
    
    Also, load the backend's initially set locale as the locale property
    value until the org.freedesktop.locale1 D-Bus interface notifies
    us of a locale change on the system bus.

 addressbook/libedata-book/Makefile.am   |    2 +
 addressbook/libedata-book/e-data-book.c |  219 ++++++++++++++++++++++++++++++-
 2 files changed, 220 insertions(+), 1 deletions(-)
---
diff --git a/addressbook/libedata-book/Makefile.am b/addressbook/libedata-book/Makefile.am
index b7e9351..d795d32 100644
--- a/addressbook/libedata-book/Makefile.am
+++ b/addressbook/libedata-book/Makefile.am
@@ -9,8 +9,10 @@ libedata_book_1_2_la_CPPFLAGS = \
        -I$(top_srcdir) \
        -I$(top_srcdir)/addressbook \
        -I$(top_srcdir)/addressbook/libegdbus \
+       -I$(top_srcdir)/private \
        -I$(top_builddir) \
        -I$(top_builddir)/addressbook \
+       -I$(top_builddir)/private \
        $(DB_CFLAGS) \
        $(CAMEL_CFLAGS) \
        $(SQLITE3_CFLAGS) \
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 667af14..cbcf5b3 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -27,12 +27,14 @@
 
 #include <libebook-contacts/libebook-contacts.h>
 
+
 #include "e-data-book-factory.h"
 #include "e-data-book.h"
 #include "e-data-book-view.h"
 #include "e-book-backend.h"
 #include "e-book-backend-factory.h"
 #include "e-book-backend-sexp.h"
+#include "e-dbus-localed.h"
 
 #include "e-gdbus-book.h"
 
@@ -57,6 +59,10 @@ struct _EDataBookPrivate
        GStaticRecMutex pending_ops_lock;
        GHashTable *pending_ops; /* opid to GCancellable for still running operations */
        GHashTable *direct_ops; /* opid to DirectOperationData for still running operations */
+
+       guint localed_watch_id;
+       EDBusLocale1 *localed_proxy;
+       GCancellable *localed_cancel;
 };
 
 enum {
@@ -82,7 +88,8 @@ typedef enum {
        OP_GET_VIEW,
        OP_CANCEL_OPERATION,
        OP_CANCEL_ALL,
-       OP_CLOSE
+       OP_CLOSE,
+       OP_GET_LOCALE,
 } OperationID;
 
 typedef struct {
@@ -147,6 +154,8 @@ static void                 direct_operation_wait      (DirectOperationData *dat
 static void                 e_data_book_respond_close  (EDataBook *book,
                                                        guint opid,
                                                        GError *error);
+static DirectOperationData *op_complete                (EDataBook *book,
+                                                       guint32 opid);
 
 /* EModule's can never be free'd, however the use count can change
  * Here we ensure that there is only one ever created by way of
@@ -410,6 +419,7 @@ operation_thread (gpointer data,
 {
        OperationData *op = data;
        EBookBackend *backend;
+       const gchar *locale;
 
        backend = e_data_book_get_backend (op->book);
 
@@ -499,6 +509,16 @@ operation_thread (gpointer data,
                }
                g_free (op->d.query);
                break;
+
+       case OP_GET_LOCALE:
+
+               op_complete (op->book, op->id);
+               locale = e_book_backend_get_locale (backend);
+               e_gdbus_book_emit_get_locale_done (op->book->priv->gdbus_object, op->id, NULL, locale);
+
+               break;
+
+
        case OP_CANCEL_OPERATION:
                g_static_rec_mutex_lock (&op->book->priv->pending_ops_lock);
 
@@ -1106,6 +1126,21 @@ impl_Book_close (EGdbusBook *object,
        return TRUE;
 }
 
+static gboolean
+impl_Book_get_locale (EGdbusBook *object,
+                     GDBusMethodInvocation *invocation,
+                     EDataBook *book)
+{
+       OperationData *op;
+
+       op = op_new (OP_GET_LOCALE, book);
+
+       e_gdbus_book_complete_get_locale (book->priv->gdbus_object, invocation, op->id);
+       e_operation_pool_push (ops_pool, op);
+
+       return TRUE;
+}
+
 void
 e_data_book_respond_open (EDataBook *book,
                           guint opid,
@@ -1672,6 +1707,154 @@ e_data_book_register_gdbus_object (EDataBook *book,
        return e_gdbus_book_register_object (book->priv->gdbus_object, connection, object_path, error);
 }
 
+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))
+                               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))
+                               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 = book->priv->backend;
+
+       if (backend) {
+               const gchar * const *locale;
+               gchar *interpreted_locale;
+
+               locale = e_dbus_locale1_get_locale (locale_proxy);
+               interpreted_locale = data_book_interpret_locale (locale);
+
+               e_book_backend_set_locale (backend, interpreted_locale);
+
+               e_gdbus_book_emit_locale_changed (book->priv->gdbus_object, interpreted_locale);
+
+               g_free (interpreted_locale);
+       }
+}
+
+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 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_DO_NOT_AUTO_START,
+                                 "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)
@@ -1738,6 +1921,9 @@ data_book_set_gdbus_object (EDataBook *ebook,
        g_signal_connect (
                gdbus_object, "handle-close",
                G_CALLBACK (impl_Book_close), ebook);
+       g_signal_connect (
+               gdbus_object, "handle-get-locale",
+               G_CALLBACK (impl_Book_get_locale), ebook);
 }
 
 static void
@@ -1802,6 +1988,17 @@ 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;
+       }
+
        /* Chain up to parent's dispose() metnod. */
        G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
 }
@@ -1830,6 +2027,9 @@ data_book_finalize (GObject *object)
                priv->gdbus_object = 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);
 }
@@ -1892,6 +2092,7 @@ e_data_book_new (EBookBackend *backend)
 {
        EGdbusBook *gdbus_object;
        EDataBook *book;
+       GBusType bus_type = G_BUS_TYPE_SYSTEM;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
 
@@ -1907,6 +2108,22 @@ e_data_book_new (EBookBackend *backend)
        /* This will be NULL for a backend that does not support direct read access */
        book->priv->direct_book = e_book_backend_get_direct_book (backend);
 
+       /* 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 book;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]