57da029
From 9bd9e83179e863c8bd25da423d6c69f57c3317ba Mon Sep 17 00:00:00 2001
57da029
From: Peter Hutterer <peter.hutterer@who-t.net>
57da029
Date: Wed, 4 Feb 2009 11:50:18 +1000
57da029
Subject: [PATCH] config: if we can't connect to HAL, listen for a startup notification.
57da029
57da029
If HAL isn't available when we try to connect, the registered NameOwnerChanged
57da029
signal handler waits until HAL is available. Once we connected to HAL, we
57da029
unregister the signal handler again.
57da029
This allows HAL to be started in parallel or after the server has started.
57da029
57da029
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
57da029
---
57da029
 config/hal.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
57da029
 1 files changed, 105 insertions(+), 6 deletions(-)
57da029
57da029
diff --git a/config/hal.c b/config/hal.c
57da029
index 8dfbb07..36fa839 100644
57da029
--- a/config/hal.c
57da029
+++ b/config/hal.c
57da029
@@ -467,11 +467,10 @@ disconnect_hook(void *data)
57da029
     info->system_bus = NULL;
57da029
 }
57da029
 
57da029
-static void
57da029
-connect_hook(DBusConnection *connection, void *data)
57da029
+static BOOL
57da029
+connect_and_register(DBusConnection *connection, struct config_hal_info *info)
57da029
 {
57da029
     DBusError error;
57da029
-    struct config_hal_info *info = data;
57da029
     char **devices;
57da029
     int num_devices, i;
57da029
 
57da029
@@ -479,8 +478,10 @@ connect_hook(DBusConnection *connection, void *data)
57da029
 
57da029
     dbus_error_init(&error);
57da029
 
57da029
-    if (!info->hal_ctx)
57da029
-        info->hal_ctx = libhal_ctx_new();
57da029
+    if (info->hal_ctx)
57da029
+        return TRUE; /* already registered, pretend we did something */
57da029
+
57da029
+    info->hal_ctx = libhal_ctx_new();
57da029
     if (!info->hal_ctx) {
57da029
         LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n");
57da029
         goto out_err;
57da029
@@ -512,7 +513,7 @@ connect_hook(DBusConnection *connection, void *data)
57da029
 
57da029
     dbus_error_free(&error);
57da029
 
57da029
-    return;
57da029
+    return TRUE;
57da029
 
57da029
 out_ctx2:
57da029
     if (!libhal_ctx_shutdown(info->hal_ctx, &error))
57da029
@@ -526,6 +527,104 @@ out_err:
57da029
     info->hal_ctx = NULL;
57da029
     info->system_bus = NULL;
57da029
 
57da029
+    return FALSE;
57da029
+}
57da029
+
57da029
+
57da029
+/**
57da029
+ * Handle NewOwnerChanged signals to deal with HAL startup at X server runtime.
57da029
+ *
57da029
+ * NewOwnerChanged is send once when HAL shuts down, and once again when it
57da029
+ * comes back up. Message has three arguments, first is the name
57da029
+ * (org.freedesktop.Hal), the second one is the old owner, third one is new
57da029
+ * owner.
57da029
+ */
57da029
+static DBusHandlerResult
57da029
+ownerchanged_handler(DBusConnection *connection, DBusMessage *message, void *data)
57da029
+{
57da029
+    int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
57da029
+
57da029
+    if (dbus_message_is_signal(message,
57da029
+                               "org.freedesktop.DBus",
57da029
+                               "NameOwnerChanged")) {
57da029
+        DBusError error;
57da029
+        char *name, *old_owner, *new_owner;
57da029
+
57da029
+        dbus_error_init(&error);
57da029
+        dbus_message_get_args(message, &error,
57da029
+                              DBUS_TYPE_STRING, &name,
57da029
+                              DBUS_TYPE_STRING, &old_owner,
57da029
+                              DBUS_TYPE_STRING, &new_owner,
57da029
+                              DBUS_TYPE_INVALID);
57da029
+
57da029
+        if (dbus_error_is_set(&error)) {
57da029
+            ErrorF("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n",
57da029
+                   error.name, error.message);
57da029
+        } else if (name && strcmp(name, "org.freedesktop.Hal") == 0) {
57da029
+
57da029
+            if (!old_owner || !strlen(old_owner)) {
57da029
+                DebugF("[config/hal] HAL startup detected.\n");
57da029
+                if (connect_and_register(connection, (struct config_hal_info*)data))
57da029
+                    dbus_connection_unregister_object_path(connection,
57da029
+                                                     "/org/freedesktop/DBus");
57da029
+                else
57da029
+                    ErrorF("[config/hal] Failed to connect to HAL bus.\n");
57da029
+            }
57da029
+
57da029
+            ret = DBUS_HANDLER_RESULT_HANDLED;
57da029
+        }
57da029
+        dbus_error_free(&error);
57da029
+    }
57da029
+
57da029
+    return ret;
57da029
+}
57da029
+
57da029
+/**
57da029
+ * Register a handler for the NameOwnerChanged signal.
57da029
+ */
57da029
+static BOOL
57da029
+listen_for_startup(DBusConnection *connection, void *data)
57da029
+{
57da029
+    DBusObjectPathVTable vtable = { .message_function = ownerchanged_handler, };
57da029
+    DBusError error;
57da029
+    const char MATCH_RULE[] = "sender='org.freedesktop.DBus',"
57da029
+                              "interface='org.freedesktop.DBus',"
57da029
+                              "type='signal',"
57da029
+                              "path='/org/freedesktop/DBus',"
57da029
+                              "member='NameOwnerChanged'";
57da029
+    int rc = FALSE;
57da029
+
57da029
+    dbus_error_init(&error);
57da029
+    dbus_bus_add_match(connection, MATCH_RULE, &error);
57da029
+    if (!dbus_error_is_set(&error)) {
57da029
+        if (dbus_connection_register_object_path(connection,
57da029
+                                                  "/org/freedesktop/DBus",
57da029
+                                                  &vtable,
57da029
+                                                  data))
57da029
+            rc = TRUE;
57da029
+        else
57da029
+            ErrorF("[config/hal] cannot register object path.\n");
57da029
+    } else {
57da029
+        ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name,
57da029
+                error.message);
57da029
+        ErrorF("[config/hal] cannot detect a HAL startup.\n");
57da029
+    }
57da029
+
57da029
+    dbus_error_free(&error);
57da029
+
57da029
+    return rc;
57da029
+}
57da029
+
57da029
+static void
57da029
+connect_hook(DBusConnection *connection, void *data)
57da029
+{
57da029
+    struct config_hal_info *info = data;
57da029
+
57da029
+    if (listen_for_startup(connection, data) &&
57da029
+        connect_and_register(connection, info))
57da029
+        dbus_connection_unregister_object_path(connection,
57da029
+                                               "/org/freedesktop/DBus");
57da029
+
57da029
     return;
57da029
 }
57da029
 
57da029
-- 
57da029
1.6.0.6
57da029