[tracker/collation-gconf-locale: 1/20] libtracker-common: Locale retrieval from gconf implemented
- From: Aleksander Morgado <aleksm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/collation-gconf-locale: 1/20] libtracker-common: Locale retrieval from gconf implemented
- Date: Tue, 30 Nov 2010 17:09:11 +0000 (UTC)
commit 37321f7310bb7e81e66af6d48a763b3a28bde1ab
Author: Aleksander Morgado <aleksander lanedo com>
Date: Wed Sep 1 18:49:28 2010 +0200
libtracker-common: Locale retrieval from gconf implemented
configure.ac | 17 ++
src/libtracker-common/Makefile.am | 6 +-
src/libtracker-common/tracker-common.h | 1 +
src/libtracker-common/tracker-locale.c | 409 ++++++++++++++++++++++++++++++++
src/libtracker-common/tracker-locale.h | 64 +++++
5 files changed, 495 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5d96031..ade5661 100644
--- a/configure.ac
+++ b/configure.ac
@@ -606,6 +606,23 @@ AC_ARG_ENABLE(maemo,
AM_CONDITIONAL(HAVE_MAEMO, test "x$enable_maemo" = "xyes")
+if test "x$enable_maemo" = "xyes" ; then
+
+ AC_DEFINE(HAVE_MAEMO, 1, [Define if we enable Maemo specific features])
+
+ PKG_CHECK_MODULES(GCONF,
+ [gconf-2.0],
+ [have_gconf=yes],
+ [have_gconf=no])
+
+ LIBTRACKER_COMMON_CFLAGS="$LIBTRACKER_COMMON_CFLAGS $GCONF_CFLAGS"
+ LIBTRACKER_COMMON_LIBS="$LIBTRACKER_COMMON_LIBS $GCONF_LIBS"
+
+ if test "x$have_gconf" != "xyes"; then
+ AC_MSG_ERROR([Couldn't find gconf, needed when enabling maemo support])
+ fi
+fi
+
####################################################################
# Check for SQLite
####################################################################
diff --git a/src/libtracker-common/Makefile.am b/src/libtracker-common/Makefile.am
index 4020384..b230a58 100644
--- a/src/libtracker-common/Makefile.am
+++ b/src/libtracker-common/Makefile.am
@@ -43,7 +43,8 @@ libtracker_common_la_SOURCES = \
tracker-log.c \
tracker-type-utils.c \
tracker-utils.c \
- tracker-crc32.c
+ tracker-crc32.c \
+ tracker-locale.c
noinst_HEADERS = \
$(power_headers) \
@@ -59,7 +60,8 @@ noinst_HEADERS = \
tracker-ontologies.h \
tracker-type-utils.h \
tracker-utils.h \
- tracker-crc32.h
+ tracker-crc32.h \
+ tracker-locale.h
if HAVE_TRACKER_FTS
libtracker_common_la_SOURCES += \
diff --git a/src/libtracker-common/tracker-common.h b/src/libtracker-common/tracker-common.h
index fbd0550..7fcfc72 100644
--- a/src/libtracker-common/tracker-common.h
+++ b/src/libtracker-common/tracker-common.h
@@ -41,6 +41,7 @@
#include "tracker-power.h"
#include "tracker-type-utils.h"
#include "tracker-utils.h"
+#include "tracker-locale.h"
#undef __LIBTRACKER_COMMON_INSIDE__
diff --git a/src/libtracker-common/tracker-locale.c b/src/libtracker-common/tracker-locale.c
new file mode 100644
index 0000000..9921418
--- /dev/null
+++ b/src/libtracker-common/tracker-locale.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2010 Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <locale.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "tracker-locale.h"
+
+#ifdef HAVE_MAEMO
+#include <gconf/gconf-client.h>
+#endif /* HAVE_MAEMO */
+
+#ifdef HAVE_MAEMO
+/* Mutex to sync access to the current locale values */
+static GStaticMutex locales_mutex = G_STATIC_MUTEX_INIT;
+static GStaticMutex subscribers_mutex = G_STATIC_MUTEX_INIT;
+#define LOCK_LOCALES g_static_mutex_lock (&locales_mutex)
+#define UNLOCK_LOCALES g_static_mutex_unlock (&locales_mutex)
+#define LOCK_SUBSCRIBERS g_static_mutex_lock (&subscribers_mutex)
+#define UNLOCK_SUBSCRIBERS g_static_mutex_unlock (&subscribers_mutex)
+#else
+/* If not using gconf locales, no need to acquire/release any lock */
+#define LOCK_LOCALES
+#define UNLOCK_LOCALES
+#endif /* HAVE_MAEMO */
+
+/* Current locales in use. They will be stored in heap and available throughout
+ * the whole program execution, so will be reported as still reachable by Valgrind.
+ */
+static gchar *current_locales[TRACKER_LOCALE_LAST];
+
+static gchar *locale_names[TRACKER_LOCALE_LAST] = {
+ "TRACKER_LOCALE_LANGUAGE",
+ "TRACKER_LOCALE_TIME",
+ "TRACKER_LOCALE_COLLATE",
+ "TRACKER_LOCALE_NUMERIC",
+ "TRACKER_LOCALE_MONETARY"
+};
+
+/* Already initialized? */
+static gboolean initialized;
+
+#ifdef HAVE_MAEMO
+
+/* If this envvar is set, even if we have meegotouch locales in gconf,
+ * we'll still use envvars */
+#define DISABLE_MEEGOTOUCH_LOCALE_ENV "DISABLE_MEEGOTOUCH_LOCALE"
+
+/* Base dir for all gconf locale values */
+#define MEEGOTOUCH_LOCALE_DIR "/meegotouch/i18n"
+
+/* gconf keys for tracker locales, as defined in:
+ * http://apidocs.meego.com/mtf/i18n.html
+ */
+static const gchar *gconf_locales[TRACKER_LOCALE_LAST] = {
+ MEEGOTOUCH_LOCALE_DIR "/language",
+ MEEGOTOUCH_LOCALE_DIR "/lc_time",
+ MEEGOTOUCH_LOCALE_DIR "/lc_collate",
+ MEEGOTOUCH_LOCALE_DIR "/lc_numeric",
+ MEEGOTOUCH_LOCALE_DIR "/lc_monetary"
+};
+
+/* Structure to hold the notification data of each subscriber */
+typedef struct {
+ TrackerLocaleID id;
+ TrackerLocaleNotifyFunc func;
+ gpointer user_data;
+ GFreeFunc destroy_notify;
+} TrackerLocaleNotification;
+
+/* List of subscribers which want to get notified of locale changes */
+static GSList *subscribers;
+
+/* The gconf client, which will be created once at initialization and
+ * the reference will never be destroyed, so will be reported as still
+ * reachable by Valgrind */
+static GConfClient *client;
+
+
+static void
+tracker_locale_set (TrackerLocaleID id,
+ const gchar *value)
+{
+ if (current_locales[id]) {
+ g_debug ("Locale '%s' was changed from '%s' to '%s'",
+ locale_names[id],
+ current_locales[id],
+ value);
+ g_free (current_locales[id]);
+ } else {
+ g_debug ("Locale '%s' was set to '%s'",
+ locale_names[id],
+ value);
+ }
+
+ /* Store the new one */
+ current_locales[id] = g_strdup (value);
+
+ /* And also set the new one in the corresponding envvar */
+ switch (id) {
+ case TRACKER_LOCALE_LANGUAGE:
+ g_setenv ("LANG", value, TRUE);
+ break;
+ case TRACKER_LOCALE_TIME:
+ setlocale (LC_TIME, value);
+ break;
+ case TRACKER_LOCALE_COLLATE:
+ setlocale (LC_COLLATE, value);
+ break;
+ case TRACKER_LOCALE_NUMERIC:
+ setlocale (LC_NUMERIC, value);
+ break;
+ case TRACKER_LOCALE_MONETARY:
+ setlocale (LC_MONETARY, value);
+ break;
+ case TRACKER_LOCALE_LAST:
+ /* Make compiler happy */
+ g_warn_if_reached ();
+ break;
+ }
+}
+
+static void
+tracker_locale_gconf_notify_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ guint i;
+ GConfValue *value;
+ GSList *li;
+ const gchar *string_value;
+
+ /* Find the proper locale to change */
+ for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
+ if (strcmp (gconf_locales[i], gconf_entry_get_key (entry)) == 0) {
+ break;
+ }
+ }
+
+ /* Oh, not found? */
+ if (i == TRACKER_LOCALE_LAST) {
+ g_debug ("Skipping change on gconf key '%s' as not really needed",
+ gconf_entry_get_key (entry));
+ return;
+ }
+
+ /* Ensure a proper value was set */
+ value = gconf_entry_get_value (entry);
+ if (!value) {
+ g_warning ("Locale value for '%s' cannot be NULL, not changing %s",
+ gconf_locales[i],
+ locale_names[i]);
+ return;
+ }
+
+ /* It must be a string */
+ if (value->type != GCONF_VALUE_STRING) {
+ g_warning ("Locale value for '%s' must be a string, not changing %s",
+ gconf_locales[i],
+ locale_names[i]);
+ return;
+ }
+
+ string_value = gconf_value_get_string (value);
+
+ /* String must have a length > 0 */
+ if (!string_value ||
+ strlen (string_value) == 0) {
+ g_warning ("Locale value for '%s' must not be empty, not changing %s",
+ gconf_locales[i],
+ locale_names[i]);
+ return;
+ }
+
+ /* Protect the locale change with the lock */
+ LOCK_LOCALES;
+ tracker_locale_set (i, gconf_value_get_string (value));
+ UNLOCK_LOCALES;
+
+ /* Now, if any subscriber, notify the locale change.
+ * NOTE!!!! The callback MUST NOT perform any action
+ * that may change the list of subscribers, or the
+ * program will get locked. */
+ LOCK_SUBSCRIBERS;
+ for (li = subscribers; li; li = g_slist_next (li)) {
+ TrackerLocaleNotification *data = li->data;
+
+ if (i == data->id) {
+ g_debug ("Notifying locale '%s' change to subscriber '%p'",
+ locale_names[i],
+ data);
+ data->func (i, data->user_data);
+ }
+ }
+ UNLOCK_SUBSCRIBERS;
+}
+
+#endif /* HAVE_MAEMO */
+
+static void
+tracker_locale_init (void)
+{
+ guint i;
+
+#ifdef HAVE_MAEMO
+ if (g_getenv (DISABLE_MEEGOTOUCH_LOCALE_ENV)) {
+ g_message ("Retrieving locale from GConf is DISABLED");
+ } else {
+ GError *error = NULL;
+
+ g_message ("Retrieving locale from GConf is ENABLED");
+
+ /* Get default gconf client to query the locale values */
+ client = gconf_client_get_default ();
+
+ /* We want to be notified when locales are changed in gconf */
+ gconf_client_add_dir (client,
+ MEEGOTOUCH_LOCALE_DIR,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ &error);
+ if (error) {
+ g_warning ("Cannot add dir '%s' in gconf client: '%s'",
+ MEEGOTOUCH_LOCALE_DIR,
+ error->message);
+ g_clear_error (&error);
+ } else {
+ /* Request notifications */
+ gconf_client_notify_add (client,
+ MEEGOTOUCH_LOCALE_DIR,
+ tracker_locale_gconf_notify_cb,
+ NULL,
+ NULL,
+ &error);
+ if (error) {
+ g_warning ("Cannot request notifications under dir '%s' in "
+ "gconf client: '%s'",
+ MEEGOTOUCH_LOCALE_DIR,
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ /* And initialize all, should have been all preloaded in the
+ * client already */
+ for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
+ GConfValue *val;
+
+ /* Get the gconf key, if any */
+ val = gconf_client_get (client,
+ gconf_locales[i],
+ &error);
+ if (!val) {
+ g_warning ("Couldn't get value for key '%s'"
+ " from gconf: '%s'"
+ " Defaulting to environment locale.",
+ gconf_locales[i],
+ error ? error->message : "no such key");
+ g_clear_error (&error);
+ } else if (val->type != GCONF_VALUE_STRING) {
+ g_warning ("Wrong type for '%s' key in gconf..."
+ " Defaulting to environment locale.",
+ gconf_locales[i]);
+ gconf_value_free (val);
+ } else {
+ /* Set the new locale */
+ tracker_locale_set (i, gconf_value_get_string (val));
+ gconf_value_free (val);
+ }
+ }
+ }
+#endif /* HAVE_MAEMO */
+
+ /* Initialize those not retrieved from gconf, or if not in maemo */
+ for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
+ if (!current_locales[i]) {
+ const gchar *env_locale;
+
+ switch (i) {
+ case TRACKER_LOCALE_LANGUAGE:
+ env_locale = g_getenv ("LANG");
+ break;
+ case TRACKER_LOCALE_TIME:
+ env_locale = setlocale (LC_TIME, NULL);
+ break;
+ case TRACKER_LOCALE_COLLATE:
+ env_locale = setlocale (LC_COLLATE, NULL);
+ break;
+ case TRACKER_LOCALE_NUMERIC:
+ env_locale = setlocale (LC_NUMERIC, NULL);
+ break;
+ case TRACKER_LOCALE_MONETARY:
+ env_locale = setlocale (LC_MONETARY, NULL);
+ break;
+ case TRACKER_LOCALE_LAST:
+ /* Make compiler happy. The for loop avoids
+ * this from happening. */
+ break;
+ }
+
+ if (!env_locale) {
+ g_warning ("Locale '%d' is not set, defaulting to C locale", i);
+ tracker_locale_set (i, "C");
+ } else {
+ tracker_locale_set (i, env_locale);
+ }
+ }
+ }
+
+ /* So we're initialized */
+ initialized = TRUE;
+}
+
+gchar *
+tracker_locale_get (TrackerLocaleID id)
+{
+ gchar *locale;
+
+ /* Lock even before checking if initialized, so that initialization is
+ * not done twice */
+ LOCK_LOCALES;
+
+ /* Initialize if not already done */
+ if (!initialized)
+ tracker_locale_init ();
+
+ /* Always return a duplicated string, as the locale may change at any
+ * moment */
+ locale = g_strdup (current_locales[id]);
+
+ UNLOCK_LOCALES;
+
+ return locale;
+}
+
+gpointer
+tracker_locale_notify_add (TrackerLocaleID id,
+ TrackerLocaleNotifyFunc func,
+ gpointer user_data,
+ GFreeFunc destroy_notify)
+{
+#ifdef HAVE_MAEMO
+ TrackerLocaleNotification *data;
+
+ g_assert (func);
+
+ data = g_slice_new (TrackerLocaleNotification);
+ data->id = id;
+ data->func = func;
+ data->user_data = user_data;
+ data->destroy_notify = destroy_notify;
+
+ /* Lock list, we cannot! use the same lock as for locales here... */
+ LOCK_SUBSCRIBERS;
+ subscribers = g_slist_prepend (subscribers, data);
+ UNLOCK_SUBSCRIBERS;
+
+ return data;
+#else
+ /* If not using gconf locales, this is a no-op... */
+ return NULL;
+#endif /* HAVE_MAEMO */
+}
+
+void
+tracker_locale_notify_remove (gpointer notification_id)
+{
+#ifdef HAVE_MAEMO
+ GSList *li;
+
+ LOCK_SUBSCRIBERS;
+ li = g_slist_find (subscribers, notification_id);
+ if (li) {
+ TrackerLocaleNotification *data = li->data;
+
+ /* Remove item from list of subscribers */
+ subscribers = g_slist_delete_link (subscribers, li);
+
+ /* Call the provided destroy_notify if any. */
+ if (data->destroy_notify)
+ data->destroy_notify (data->user_data);
+ /* And fully dispose the notification data */
+ g_slice_free (TrackerLocaleNotification, data);
+ }
+ UNLOCK_SUBSCRIBERS;
+#else
+ /* If not using gconf locales, this is a no-op... */
+#endif /* HAVE_MAEMO */
+}
diff --git a/src/libtracker-common/tracker-locale.h b/src/libtracker-common/tracker-locale.h
new file mode 100644
index 0000000..49dac0b
--- /dev/null
+++ b/src/libtracker-common/tracker-locale.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __LIBTRACKER_COMMON_LOCALE_H__
+#define __LIBTRACKER_COMMON_LOCALE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#if !defined (__LIBTRACKER_COMMON_INSIDE__) && !defined (TRACKER_COMPILATION)
+#error "only <libtracker-common/tracker-common.h> must be included directly."
+#endif
+
+/* Type of locales supported in tracker */
+typedef enum {
+ TRACKER_LOCALE_LANGUAGE,
+ TRACKER_LOCALE_TIME,
+ TRACKER_LOCALE_COLLATE,
+ TRACKER_LOCALE_NUMERIC,
+ TRACKER_LOCALE_MONETARY,
+ TRACKER_LOCALE_LAST
+} TrackerLocaleID;
+
+/* Callback for the notification of locale changes */
+typedef void (* TrackerLocaleNotifyFunc) (TrackerLocaleID id,
+ gpointer user_data);
+
+/* Get the current locale of the given type.
+ * Note that it returns a newly-allocated string which should be g_free()-ed
+ */
+gchar *tracker_locale_get (TrackerLocaleID id);
+
+/* Adds a new subscriber to locale change notifications.
+ * Returns a pointer which identifies the subscription.
+ */
+gpointer tracker_locale_notify_add (TrackerLocaleID id,
+ TrackerLocaleNotifyFunc func,
+ gpointer user_data,
+ GFreeFunc destroy_notify);
+
+/* Remove a given subscriber, passing the id you got in _add() */
+void tracker_locale_notify_remove (gpointer notification_id);
+
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_COMMON_LOCALE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]