[tracker/tracker-0.10] libtracker-common: Listen for changes on GConf using DBus directly for meegotouch locales
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-0.10] libtracker-common: Listen for changes on GConf using DBus directly for meegotouch locales
- Date: Thu, 7 Apr 2011 13:43:51 +0000 (UTC)
commit 609665e6b048417872e61a1735f1f326a4e5a971
Author: Philip Van Hoof <philip codeminded be>
Date: Mon Apr 4 12:23:09 2011 +0200
libtracker-common: Listen for changes on GConf using DBus directly for meegotouch locales
Fixes NB#240272.
src/libtracker-common/tracker-locale-gconfdbus.c | 334 +++++++++++++++++++++-
src/libtracker-common/tracker-locale-gconfdbus.h | 6 +
src/libtracker-common/tracker-locale.c | 10 +
3 files changed, 341 insertions(+), 9 deletions(-)
---
diff --git a/src/libtracker-common/tracker-locale-gconfdbus.c b/src/libtracker-common/tracker-locale-gconfdbus.c
index 538d66d..ea54191 100644
--- a/src/libtracker-common/tracker-locale-gconfdbus.c
+++ b/src/libtracker-common/tracker-locale-gconfdbus.c
@@ -46,6 +46,11 @@
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
@@ -58,6 +63,157 @@ static const gchar *gconf_locales[TRACKER_LOCALE_LAST] = {
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 = NULL, *value = NULL;
+ const gchar *schema = NULL, *database = NULL;
+ const gchar *namespace_name = NULL;
+ 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));
+ return;
+ }
+
+ /* 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 gchar *
get_value_from_config (const gchar *key_in)
{
@@ -104,13 +260,49 @@ get_value_from_config (const gchar *key_in)
return val;
}
+
+static void
+on_gconfd_dbus_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ guint i;
+
+ service_running = TRUE;
+ add_notify ();
+
+ /* And (re)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);
+ }
+ }
+}
+
+static void
+on_gconfd_dbus_disappeared (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ service_running = FALSE;
+}
+
void
tracker_locale_gconfdbus_init (void)
{
if (!g_getenv (TRACKER_DISABLE_MEEGOTOUCH_LOCALE_ENV)) {
- guint i;
GError *error = NULL;
GVariant *reply;
+ GDBusInterfaceVTable interface_vtable = {
+ handle_method_call,
+ handle_get_property,
+ handle_set_property
+ };
g_message ("Retrieving locale from GConf is ENABLED");
@@ -122,6 +314,8 @@ tracker_locale_gconfdbus_init (void)
return;
}
+ service_running = TRUE;
+
reply = g_dbus_connection_call_sync (connection,
GCONF_DBUS_SERVICE,
GCONF_DBUS_SERVER_OBJECT,
@@ -145,28 +339,150 @@ tracker_locale_gconfdbus_init (void)
g_variant_unref (reply);
- /* And initialize all */
- for (i = 0; i < TRACKER_LOCALE_LAST; i++) {
- gchar *str;
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &error);
- str = get_value_from_config (gconf_locales[i]);
- if (str) {
- tracker_locale_set (i, str);
- g_free (str);
- }
+ 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;
}
+
+ 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);
}
}
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
index 0ca2691..130a0c0 100644
--- a/src/libtracker-common/tracker-locale-gconfdbus.h
+++ b/src/libtracker-common/tracker-locale-gconfdbus.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
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 82058aa..f2e91fa 100644
--- a/src/libtracker-common/tracker-locale.c
+++ b/src/libtracker-common/tracker-locale.c
@@ -178,10 +178,20 @@ tracker_locale_notify_add (TrackerLocaleID id,
gpointer user_data,
GFreeFunc destroy_notify)
{
+#ifdef HAVE_MAEMO
+ 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;
+#endif /* HAVE_MAEMO */
}
void
tracker_locale_notify_remove (gpointer notification_id)
{
+#ifdef HAVE_MAEMO
+ return tracker_locale_gconfdbus_notify_remove (notification_id);
+#else
+ /* If not using gconf locales, this is a no-op... */
+#endif /* HAVE_MAEMO */
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]