[tracker/gconf-dbus] libtracker-common: Use GDBus manually for gconf-dbus, gconfclient isn't thread safe
- From: Philip Van Hoof <pvanhoof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/gconf-dbus] libtracker-common: Use GDBus manually for gconf-dbus, gconfclient isn't thread safe
- Date: Fri, 1 Apr 2011 15:22:40 +0000 (UTC)
commit e073eaa5d414f657efa13a06b41f2e06d1556842
Author: Philip Van Hoof <philip codeminded be>
Date: Fri Apr 1 14:09:38 2011 +0200
libtracker-common: Use GDBus manually for gconf-dbus, gconfclient isn't thread safe
src/libtracker-common/Makefile.am | 5 +
src/libtracker-common/tracker-locale-gconfdbus.c | 483 ++++++++++++++++++++++
src/libtracker-common/tracker-locale-gconfdbus.h | 44 ++
src/libtracker-common/tracker-locale.c | 275 ++-----------
src/libtracker-common/tracker-locale.h | 19 +-
5 files changed, 567 insertions(+), 259 deletions(-)
---
diff --git a/src/libtracker-common/Makefile.am b/src/libtracker-common/Makefile.am
index 7c2c7c0..a5c5711 100644
--- a/src/libtracker-common/Makefile.am
+++ b/src/libtracker-common/Makefile.am
@@ -64,6 +64,11 @@ libtracker_common_la_SOURCES += tracker-language.c
noinst_HEADERS += tracker-language.h
endif
+if HAVE_MAEMO
+libtracker_common_la_SOURCES += tracker-locale-gconfdbus.c
+noinst_HEADERS += tracker-locale-gconfdbus.h
+endif
+
libtracker_common_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/src/libtracker-common/tracker-locale-gconfdbus.c b/src/libtracker-common/tracker-locale-gconfdbus.c
new file mode 100644
index 0000000..2b44663
--- /dev/null
+++ b/src/libtracker-common/tracker-locale-gconfdbus.c
@@ -0,0 +1,483 @@
+/*
+ * 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 <glib-object.h>
+#include <gio/gio.h>
+
+#include "tracker-locale-gconfdbus.h"
+
+#define GCONF_DBUS_SERVICE "org.gnome.GConfDBus"
+#define GCONF_DBUS_SERVER_INTERFACE "org.gnome.GConfDBus.Server"
+#define GCONF_DBUS_DATABASE_INTERFACE "org.gnome.GConfDBus.Database"
+#define GCONF_DBUS_SERVER_OBJECT "/org/gnome/GConfDBus/Server"
+#define GCONF_DBUS_CLIENT_OBJECT "/org/gnome/GConfDBus/Client"
+#define GCONF_DBUS_CLIENT_INTERFACE "org.gnome.GConfDBus.Client"
+
+/* Base dir for all gconf locale values */
+#define MEEGOTOUCH_LOCALE_DIR "/meegotouch/i18n"
+
+#define TRACKER_DISABLE_MEEGOTOUCH_LOCALE_ENV "TRACKER_DISABLE_MEEGOTOUCH_LOCALE"
+
+static gchar*gconf_dbus_default_db = NULL;
+static GDBusConnection *connection = NULL;
+static gboolean service_running = FALSE;
+static guint watch_name_id = 0;
+static guint registration_id = 0;
+static GStaticMutex subscribers_mutex = G_STATIC_MUTEX_INIT;
+GDBusNodeInfo *introspection_data = NULL;
+
+/* gconf keys for tracker locales, as defined in:
+ * http://apidocs.meego.com/1.0/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;
+
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='" GCONF_DBUS_CLIENT_INTERFACE "'>"
+ " <method name='Notify'>"
+ " <arg type='s' name='database' direction='in' />"
+ " <arg type='s' name='namespace_section' direction='in' />"
+ " <arg type='(s(is)bsbb)' name='value' direction='in' />"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+static gboolean
+add_notify (void)
+{
+ GVariant *reply;
+ GError *error = NULL;
+
+ reply = g_dbus_connection_call_sync (connection,
+ GCONF_DBUS_SERVICE,
+ gconf_dbus_default_db,
+ GCONF_DBUS_DATABASE_INTERFACE,
+ "AddNotify",
+ g_variant_new ("(s)", MEEGOTOUCH_LOCALE_DIR),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (error) {
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ g_variant_unref (reply);
+
+ return TRUE;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ /* Takes place in mainloop */
+
+ if (g_strcmp0 (method_name, "Notify") == 0) {
+ const gchar *key, *value, *schema, *database, *namespace_name;
+ gboolean is_set, is_default, is_writable;
+ gint type, i;
+ GSList *li;
+
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss(s(is)bsbb))"))) {
+
+ g_variant_get (parameters, "(&s&s(&s(i&s)b&sbb))",
+ &database, &namespace_name,
+ &key, &type, &value,
+ &is_set, &schema,
+ &is_default, &is_writable,
+ NULL);
+
+ /* Find the proper locale to change */
+ for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
+ if (strcmp (gconf_locales[i], key) == 0) {
+ break;
+ }
+ }
+
+ /* Oh, not found? */
+ if (i == TRACKER_LOCALE_LAST) {
+ g_debug ("Skipping change on gconf key '%s' as not really needed", key);
+ return;
+ }
+
+ /* Ensure a proper value was set */
+ if (value == NULL || value[0] == '\0') {
+ g_warning ("Locale value for '%s' cannot be NULL, not changing %s",
+ gconf_locales[i],
+ tracker_locale_get_name (i));
+ }
+
+ /* This always runs from mainloop, so no need for a lock other than
+ * subscribers, which might be added and removed by threads (and are
+ * here executed by function pointer on the mainloop) */
+
+ tracker_locale_set (i, value);
+
+ g_static_mutex_lock (&subscribers_mutex);
+
+ 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'",
+ tracker_locale_get_name(i),
+ data);
+ data->func (i, data->user_data);
+ }
+ }
+
+ g_static_mutex_unlock (&subscribers_mutex);
+ }
+ }
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ return NULL;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ return TRUE;
+}
+
+static void
+on_gconfd_dbus_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ service_running = TRUE;
+ add_notify ();
+}
+
+static void
+on_gconfd_dbus_disappeared (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ service_running = FALSE;
+}
+
+
+static gchar *
+get_value_from_config (const gchar *key_in)
+{
+ const gchar *locale = setlocale (LC_CTYPE, NULL);
+ const gchar *key, *value, *schema;
+ gchar *val = NULL;
+ gboolean is_set, is_default, is_writable;
+ gint type;
+ GError *error = NULL;
+ GVariant *reply;
+
+ reply = g_dbus_connection_call_sync (connection,
+ GCONF_DBUS_SERVICE,
+ gconf_dbus_default_db,
+ GCONF_DBUS_DATABASE_INTERFACE,
+ "LookupExtended",
+ g_variant_new ("(ssb)", key_in, locale, TRUE),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (error) {
+ g_variant_unref (reply);
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+
+ return NULL;
+ }
+
+ if (g_variant_is_of_type (reply, G_VARIANT_TYPE ("((s(is)bsbb))"))) {
+ g_variant_get (reply, "((&s(i&s)b&sbb))",
+ &key, &type, &value,
+ &is_set, &schema,
+ &is_default, &is_writable,
+ NULL);
+
+ val = g_strdup (value);
+ }
+
+ g_variant_unref (reply);
+
+ return val;
+}
+
+void
+tracker_locale_gconfdbus_init (void)
+{
+ if (!g_getenv (TRACKER_DISABLE_MEEGOTOUCH_LOCALE_ENV)) {
+ GError *error = NULL;
+ GVariant *reply;
+ guint i;
+
+ GDBusInterfaceVTable interface_vtable = {
+ handle_method_call,
+ handle_get_property,
+ handle_set_property
+ };
+
+ g_message ("Retrieving locale from GConf is ENABLED");
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+
+ if (error) {
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+
+ return;
+ }
+
+ service_running = TRUE;
+
+ reply = g_dbus_connection_call_sync (connection,
+ GCONF_DBUS_SERVICE,
+ GCONF_DBUS_SERVER_OBJECT,
+ GCONF_DBUS_SERVER_INTERFACE,
+ "GetDefaultDatabase",
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+
+ if (error) {
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_variant_get (reply, "(s)", &gconf_dbus_default_db, NULL);
+
+ g_variant_unref (reply);
+
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &error);
+
+ if (error) {
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ registration_id =
+ g_dbus_connection_register_object (connection,
+ GCONF_DBUS_CLIENT_OBJECT,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL,
+ NULL,
+ &error);
+
+ if (error) {
+ g_critical ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ if (add_notify ()) {
+ watch_name_id = g_bus_watch_name_on_connection (connection,
+ GCONF_DBUS_SERVICE,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ on_gconfd_dbus_appeared,
+ on_gconfd_dbus_disappeared,
+ NULL, NULL);
+ }
+
+ /* And initialize all */
+ for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
+ gchar *str;
+
+ str = get_value_from_config (gconf_locales[i]);
+ if (str) {
+ tracker_locale_set (i, str);
+ g_free (str);
+ }
+ }
+ }
+}
+
+void
+tracker_locale_gconfdbus_shutdown (void)
+{
+ if (gconf_dbus_default_db != NULL && connection != NULL) {
+ GVariant *reply;
+ GError *error = NULL;
+
+ reply = g_dbus_connection_call_sync (connection,
+ GCONF_DBUS_SERVICE,
+ gconf_dbus_default_db,
+ GCONF_DBUS_DATABASE_INTERFACE,
+ "RemoveNotify",
+ g_variant_new ("(s)", MEEGOTOUCH_LOCALE_DIR),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (error) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ } else {
+ g_variant_unref (reply);
+ }
+ }
+
+ if (watch_name_id != 0) {
+ g_bus_unwatch_name (watch_name_id);
+ watch_name_id = 0;
+ }
+
+ if (registration_id != 0) {
+ g_dbus_connection_unregister_object (connection, registration_id);
+ registration_id = 0;
+ }
+
+ g_free (gconf_dbus_default_db);
+ gconf_dbus_default_db = NULL;
+
+ if (introspection_data) {
+ g_dbus_node_info_unref (introspection_data);
+ introspection_data = NULL;
+ }
+
+ if (connection) {
+ g_object_unref (connection);
+ connection = NULL;
+ }
+}
+
+gpointer
+tracker_locale_gconfdbus_notify_add (TrackerLocaleID id,
+ TrackerLocaleNotifyFunc func,
+ gpointer user_data,
+ GFreeFunc destroy_notify)
+{
+ TrackerLocaleNotification *data;
+
+ /* Can be called from a thread */
+
+ g_assert (func != NULL);
+
+ data = g_slice_new (TrackerLocaleNotification);
+ data->id = id;
+ data->func = func;
+ data->user_data = user_data;
+ data->destroy_notify = destroy_notify;
+
+ g_static_mutex_lock (&subscribers_mutex);
+ subscribers = g_slist_prepend (subscribers, data);
+ g_static_mutex_unlock (&subscribers_mutex);
+
+ return data;
+}
+
+static gboolean
+destroy_locale_notify (gpointer data_p)
+{
+ /* Always on mainloop */
+
+ TrackerLocaleNotification *data = data_p;
+
+ /* 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);
+
+ return FALSE;
+}
+
+void
+tracker_locale_gconfdbus_notify_remove (gpointer notification_id)
+{
+ GSList *li;
+
+ /* Can be called from a thread */
+
+ g_static_mutex_lock (&subscribers_mutex);
+
+ 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);
+
+ g_idle_add (destroy_locale_notify, data);
+ }
+
+ g_static_mutex_unlock (&subscribers_mutex);
+}
diff --git a/src/libtracker-common/tracker-locale-gconfdbus.h b/src/libtracker-common/tracker-locale-gconfdbus.h
new file mode 100644
index 0000000..130a0c0
--- /dev/null
+++ b/src/libtracker-common/tracker-locale-gconfdbus.h
@@ -0,0 +1,44 @@
+/*
+ * 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_GCONFDBUS_H__
+#define __LIBTRACKER_COMMON_LOCALE_GCONFDBUS_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
+
+#include "tracker-locale.h"
+
+void tracker_locale_gconfdbus_init (void);
+void tracker_locale_gconfdbus_shutdown (void);
+
+gpointer tracker_locale_gconfdbus_notify_add (TrackerLocaleID id,
+ TrackerLocaleNotifyFunc func,
+ gpointer user_data,
+ GFreeFunc destroy_notify);
+void tracker_locale_gconfdbus_notify_remove (gpointer notification_id);
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_COMMON_LOCALE_GCONFDBUS_H__ */
diff --git a/src/libtracker-common/tracker-locale.c b/src/libtracker-common/tracker-locale.c
index 3a00cb1..f2e91fa 100644
--- a/src/libtracker-common/tracker-locale.c
+++ b/src/libtracker-common/tracker-locale.c
@@ -27,33 +27,7 @@
#include "tracker-locale.h"
#ifdef HAVE_MAEMO
-#include <gconf/gconf-client.h>
-#endif /* HAVE_MAEMO */
-
-#ifdef HAVE_MAEMO
-
-/* In src/libtracker-sparql/tracker-init.c you'll find a first call to
- * gconf_client_get_default() in a function that has the GCC specific
- * construction attribute. This is there because GConfClient isn't thread-safe
- * or at least not "first call is in thread vs. mainloop"-safe. The reason
- * why it must be in libtracker-sparql instead of here is because this code
- * is entered using g_module_open (dlopen) by tracker_sparql_backend_load_
- * plugins_from_path: the construction attribute would only be detected at
- * dlopen, which would be in the thread that calls load_plugins_from_path
- * caused by a tracker_sparql_connection_get_async. It's a bit unfortunate
- * and perhaps ugly, but fortunately we only need it in 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
+#include "tracker-locale-gconfdbus.h"
#endif /* HAVE_MAEMO */
/* Current locales in use. They will be stored in heap and available throughout
@@ -61,7 +35,7 @@ static GStaticMutex subscribers_mutex = G_STATIC_MUTEX_INIT;
*/
static gchar *current_locales[TRACKER_LOCALE_LAST];
-static gchar *locale_names[TRACKER_LOCALE_LAST] = {
+static const gchar *locale_names[TRACKER_LOCALE_LAST] = {
"TRACKER_LOCALE_LANGUAGE",
"TRACKER_LOCALE_TIME",
"TRACKER_LOCALE_COLLATE",
@@ -71,49 +45,21 @@ static gchar *locale_names[TRACKER_LOCALE_LAST] = {
/* Already initialized? */
static gboolean initialized;
+static GStaticRecMutex locales_mutex = G_STATIC_REC_MUTEX_INIT;
-#ifdef HAVE_MAEMO
-
-/* If this envvar is set, even if we have meegotouch locales in gconf,
- * we'll still use envvars */
-#define TRACKER_DISABLE_MEEGOTOUCH_LOCALE_ENV "TRACKER_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/1.0/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;
-
-#endif /* HAVE_MAEMO */
+const gchar*
+tracker_locale_get_name (guint i)
+{
+ g_return_val_if_fail (i < TRACKER_LOCALE_LAST, NULL);
+ return locale_names[i];
+}
-static void
-locale_set (TrackerLocaleID id,
- const gchar *value)
+void
+tracker_locale_set (TrackerLocaleID id,
+ const gchar *value)
{
+ g_static_rec_mutex_lock (&locales_mutex);
+
if (current_locales[id]) {
g_debug ("Locale '%s' was changed from '%s' to '%s'",
locale_names[id],
@@ -151,87 +97,10 @@ locale_set (TrackerLocaleID id,
g_warn_if_reached ();
break;
}
-}
-
-#ifdef HAVE_MAEMO
-
-static void
-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 ||
- string_value[0] == '\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;
- 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;
+ g_static_rec_mutex_unlock (&locales_mutex);
}
-#endif /* HAVE_MAEMO */
static void
locale_init (void)
@@ -239,71 +108,7 @@ locale_init (void)
guint i;
#ifdef HAVE_MAEMO
- if (g_getenv (TRACKER_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,
- 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 */
- locale_set (i, gconf_value_get_string (val));
- gconf_value_free (val);
- }
- }
- }
+ tracker_locale_gconfdbus_init ();
#endif /* HAVE_MAEMO */
/* Initialize those not retrieved from gconf, or if not in maemo */
@@ -335,9 +140,9 @@ locale_init (void)
if (!env_locale) {
g_warning ("Locale '%d' is not set, defaulting to C locale", i);
- locale_set (i, "C");
+ tracker_locale_set (i, "C");
} else {
- locale_set (i, env_locale);
+ tracker_locale_set (i, env_locale);
}
}
}
@@ -351,19 +156,18 @@ tracker_locale_get (TrackerLocaleID id)
{
gchar *locale;
- /* Lock even before checking if initialized, so that initialization is
- * not done twice */
- LOCK_LOCALES;
+ g_static_rec_mutex_lock (&locales_mutex);
/* Initialize if not already done */
- if (!initialized)
+ if (!initialized) {
locale_init ();
+ }
/* Always return a duplicated string, as the locale may change at any
* moment */
locale = g_strdup (current_locales[id]);
- UNLOCK_LOCALES;
+ g_static_rec_mutex_unlock (&locales_mutex);
return locale;
}
@@ -375,22 +179,7 @@ tracker_locale_notify_add (TrackerLocaleID id,
GFreeFunc destroy_notify)
{
#ifdef HAVE_MAEMO
- TrackerLocaleNotification *data;
-
- g_assert (func != NULL);
-
- 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;
+ return tracker_locale_gconfdbus_notify_add (id, func, user_data, destroy_notify);
#else
/* If not using gconf locales, this is a no-op... */
return NULL;
@@ -401,23 +190,7 @@ 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;
+ return tracker_locale_gconfdbus_notify_remove (notification_id);
#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
index 49dac0b..a7c2934 100644
--- a/src/libtracker-common/tracker-locale.h
+++ b/src/libtracker-common/tracker-locale.h
@@ -39,25 +39,28 @@ typedef enum {
} TrackerLocaleID;
/* Callback for the notification of locale changes */
-typedef void (* TrackerLocaleNotifyFunc) (TrackerLocaleID id,
- gpointer user_data);
+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);
+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);
+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);
+void tracker_locale_notify_remove (gpointer notification_id);
+const gchar* tracker_locale_get_name (guint i);
+void tracker_locale_set (TrackerLocaleID id,
+ const gchar *value);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]