hal: Branch 'master' - 2 commits

David Zeuthen david at kemper.freedesktop.org
Sun Sep 10 14:28:42 PDT 2006


 doc/TODO                                       |    6 
 doc/api/tmpl/device.sgml                       |    2 
 doc/api/tmpl/hal-unused.sgml                   |   62 ++++---
 doc/api/tmpl/hald_runner.sgml                  |    3 
 doc/api/tmpl/libhal-storage.sgml               |   28 ---
 doc/api/tmpl/logger.sgml                       |   16 --
 doc/api/tmpl/runner.sgml                       |    1 
 doc/api/tmpl/util.sgml                         |   26 +++
 hald-runner/main.c                             |    9 -
 hald-runner/runner.c                           |   28 +++
 hald-runner/runner.h                           |    2 
 hald/device.c                                  |   34 ++++
 hald/device.h                                  |   10 +
 hald/hald.c                                    |   60 ++++++-
 hald/hald_dbus.c                               |   74 +++++++++
 hald/hald_runner.c                             |  152 ++++++++++++++++++-
 hald/hald_runner.h                             |   12 +
 hald/linux/addons/addon-acpi-buttons-toshiba.c |    5 
 hald/linux/addons/addon-acpi.c                 |    6 
 hald/linux/addons/addon-cpufreq.c              |    6 
 hald/linux/addons/addon-hid-ups.c              |  196 +++++++++++++++----------
 hald/linux/addons/addon-keyboard.c             |    6 
 hald/linux/addons/addon-macbookpro-backlight.c |    6 
 hald/linux/addons/addon-pmu.c                  |    6 
 hald/linux/addons/addon-storage.c              |    5 
 hald/linux/addons/addon-usb-csr.c              |    6 
 libhal/libhal.c                                |   68 ++++++++
 libhal/libhal.h                                |    3 
 partutil/.gitignore                            |    8 +
 tools/.gitignore                               |    1 
 30 files changed, 669 insertions(+), 178 deletions(-)

New commits:
diff-tree 18413734b1da6c14a0851e34d77db96f6a4ef9bb (from ed71e4e6769b8f359f7626f788a38db5f63faca8)
Author: David Zeuthen <davidz at redhat.com>
Date:   Sun Sep 10 17:28:34 2006 -0400

    require addons to call libhal_device_addon_is_ready() to make device visible
    
    Also fixup some .gitignore files and prune the TODO for finished items.

diff --git a/doc/TODO b/doc/TODO
index b7939f6..4ad533e 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -15,12 +15,6 @@ Ongoing items that always need work
 Items specifically planned for 0.5.8
 ------------------------------------
 
- - Provide a libhal_device_set_all_properties plus functions to construct
-   a LibHalPropertySet
-
- - Require that addons poke hald before the device is visible - this is for
-   addons that also probes the hardware and provide the initial state..
-
  - Move /usr/libexec to /usr/lib/hal/ - drop /usr/lib/hal/scripts -
    use /usr/lib/hal/methods
 
diff --git a/doc/api/tmpl/device.sgml b/doc/api/tmpl/device.sgml
index 5ff559e..d5a02b6 100644
--- a/doc/api/tmpl/device.sgml
+++ b/doc/api/tmpl/device.sgml
@@ -25,6 +25,8 @@ HalDevice
 @parent: 
 @udi: 
 @properties: 
+ at num_addons: 
+ at num_addons_ready: 
 
 <!-- ##### USER_FUNCTION HalDeviceAsyncCallback ##### -->
 <para>
diff --git a/doc/api/tmpl/hald_runner.sgml b/doc/api/tmpl/hald_runner.sgml
index 70ff5ff..9537d0a 100644
--- a/doc/api/tmpl/hald_runner.sgml
+++ b/doc/api/tmpl/hald_runner.sgml
@@ -81,6 +81,9 @@ hald_runner
 @device: 
 @command_line: 
 @extra_env: 
+ at cb: 
+ at data1: 
+ at data2: 
 @Returns: 
 
 
diff --git a/doc/api/tmpl/runner.sgml b/doc/api/tmpl/runner.sgml
index 78d1be6..3bdfba6 100644
--- a/doc/api/tmpl/runner.sgml
+++ b/doc/api/tmpl/runner.sgml
@@ -60,6 +60,7 @@ runner
 @r: 
 @con: 
 @msg: 
+ at out_pid: 
 @Returns: 
 
 
diff --git a/hald-runner/main.c b/hald-runner/main.c
index 6d39981..fbb7a63 100644
--- a/hald-runner/main.c
+++ b/hald-runner/main.c
@@ -94,7 +94,7 @@ handle_run(DBusConnection *con, DBusMess
 	dbus_message_iter_get_basic(&iter, &(r->timeout));
 
 	/* let run_request_run handle the reply */
-	run_request_run(r, con, msg);
+	run_request_run(r, con, msg, NULL);
 	return;
 
 malformed:
@@ -111,6 +111,7 @@ handle_start(DBusConnection *con, DBusMe
 	DBusMessage *reply;
 	DBusMessageIter iter;
 	run_request *r;
+	GPid pid;
 
 	r = new_run_request();
 	g_assert(dbus_message_iter_init(msg, &iter));
@@ -118,8 +119,12 @@ handle_start(DBusConnection *con, DBusMe
 	if (!dbus_message_iter_init(msg, &iter) || !parse_first_part(r, msg, &iter))
 		goto malformed;
 
-	if (run_request_run(r, NULL, NULL)) {
+	if (run_request_run(r, con, NULL, &pid)) {
 		reply = dbus_message_new_method_return(msg);
+		dbus_message_append_args (reply, 
+					  DBUS_TYPE_INT64, &pid,
+					  DBUS_TYPE_INVALID);
+					  
 	} else {
 		reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Failed",
 					       "Start request failed");
diff --git a/hald-runner/runner.c b/hald-runner/runner.c
index 7301233..3fb1fb2 100644
--- a/hald-runner/runner.c
+++ b/hald-runner/runner.c
@@ -58,6 +58,7 @@ typedef struct {
 	guint watch;
 	guint timeout;
 	gboolean sent_kill;
+	gboolean emit_pid_exited;
 } run_data;
 
 static void
@@ -155,9 +156,7 @@ run_exited(GPid pid, gint status, gpoint
 	if (!WIFEXITED(status)) {
 		/* No not normal termination ? crash ? */
 		send_reply(rd->con, rd->msg, HALD_RUN_FAILED, 0, NULL);
-		remove_from_hash_table(rd);
-		del_run_data(rd);
-		return;
+		goto out;
 	}
 	/* normal exit */
 	if (rd->stderr_v >= 0) {
@@ -169,7 +168,22 @@ run_exited(GPid pid, gint status, gpoint
 	if (rd->msg != NULL)
 		send_reply(rd->con, rd->msg, HALD_RUN_SUCCESS, WEXITSTATUS(status), error);
 	free_string_array(error);
+
+out:
 	remove_from_hash_table(rd);
+		
+	/* emit a signal that this PID exited */
+	if(rd->con != NULL && rd->emit_pid_exited) {
+		DBusMessage *signal;
+		signal = dbus_message_new_signal ("/org/freedesktop/HalRunner",
+						  "org.freedesktop.HalRunner",
+						  "StartedProcessExited");
+		dbus_message_append_args (signal, 
+					  DBUS_TYPE_INT64, &(rd->pid),
+					  DBUS_TYPE_INVALID);
+		dbus_connection_send(rd->con, signal, NULL);
+	}
+	
 	del_run_data(rd);
 }
 
@@ -217,7 +231,7 @@ find_program(char **argv)
 
 /* Run the given request and reply it's result on msg */
 gboolean
-run_request_run(run_request *r, DBusConnection *con, DBusMessage *msg)
+run_request_run (run_request *r, DBusConnection *con, DBusMessage *msg, GPid *out_pid)
 {
 	GPid pid;
 	GError *error = NULL;
@@ -292,6 +306,12 @@ run_request_run(run_request *r, DBusConn
 
 	/* The hash table will take care to not leak the dupped string */
 	g_hash_table_insert(udi_hash, g_strdup(r->udi), list);
+
+	/* send back PID if requested.. and only emit StartedProcessExited in this case */
+	if (out_pid != NULL) {
+		*out_pid = pid;
+		rd->emit_pid_exited = TRUE;
+	}
 	return TRUE;
 }
 
diff --git a/hald-runner/runner.h b/hald-runner/runner.h
index f15fd33..2a18f94 100644
--- a/hald-runner/runner.h
+++ b/hald-runner/runner.h
@@ -43,7 +43,7 @@ run_request *new_run_request(void);
 void del_run_request(run_request *r);
 
 /* Run the given request and reply it's result on msg */
-gboolean run_request_run(run_request *r, DBusConnection *con, DBusMessage *msg);
+gboolean run_request_run(run_request *r, DBusConnection *con, DBusMessage *msg, GPid *out_pid);
 
 /* Kill all running request for a udi */
 void run_kill_udi(gchar *udi);
diff --git a/hald/device.c b/hald/device.c
index ea7cf08..f54401f 100644
--- a/hald/device.c
+++ b/hald/device.c
@@ -35,6 +35,7 @@
 #include "device.h"
 #include "hald_marshal.h"
 #include "logger.h"
+#include "hald_runner.h"
 
 static GObjectClass *parent_class;
 
@@ -57,11 +58,14 @@ hal_device_finalize (GObject *obj)
 {
 	HalDevice *device = HAL_DEVICE (obj);
 
+	runner_device_finalized (device);
+
 #ifdef HALD_MEMLEAK_DBG
 	dbg_hal_device_object_delta--;
 	printf ("************* in finalize for udi=%s\n", device->udi);
 #endif
 
+
 	g_slist_foreach (device->properties, (GFunc) hal_property_free, NULL);
 
 	g_free (device->udi);
@@ -132,6 +136,8 @@ hal_device_init (HalDevice *device)
 
 	device->udi = g_strdup_printf ("/org/freedesktop/Hal/devices/temp/%d",
 				       temp_device_counter++);
+	device->num_addons = 0;
+	device->num_addons_ready = 0;
 }
 
 GType
@@ -1314,3 +1320,31 @@ hal_device_property_strlist_is_empty (Ha
 	return FALSE;
 }
 
+void
+hal_device_inc_num_addons (HalDevice *device)
+{
+	device->num_addons++;
+}
+
+gboolean
+hal_device_inc_num_ready_addons (HalDevice *device)
+{
+	if (hal_device_are_all_addons_ready (device)) {
+		HAL_ERROR (("In hal_device_inc_num_ready_addons for udi=%s but all addons are already ready!", 
+			    device->udi));
+		return FALSE;
+	}
+
+	device->num_addons_ready++;
+	return TRUE;
+}
+
+gboolean
+hal_device_are_all_addons_ready (HalDevice *device)
+{
+	if (device->num_addons_ready == device->num_addons) {
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
diff --git a/hald/device.h b/hald/device.h
index c31353f..a9531ba 100644
--- a/hald/device.h
+++ b/hald/device.h
@@ -41,6 +41,9 @@ struct _HalDevice {
 	char *udi;
 	
 	GSList *properties;
+
+	int num_addons;
+	int num_addons_ready;
 };
 
 struct _HalDeviceClass {
@@ -202,4 +205,11 @@ gboolean      hal_device_property_set_at
 						 enum PropertyAttribute attr,
 						 gboolean persistence);
 
+void          hal_device_inc_num_addons (HalDevice *device);
+
+gboolean      hal_device_inc_num_ready_addons (HalDevice *device);
+
+gboolean      hal_device_are_all_addons_ready (HalDevice *device);
+
+
 #endif /* DEVICE_H */
diff --git a/hald/hald.c b/hald/hald.c
index f10c087..02ae7a0 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -73,6 +73,29 @@ static HalDeviceStore *global_device_lis
 
 static HalDeviceStore *temporary_device_list = NULL;
 
+
+static void
+addon_terminated (HalDevice *device, guint32 exit_type, 
+		  gint return_code, gchar **error,
+		  gpointer data1, gpointer data2)
+{
+	HAL_INFO (("in addon_terminated for udi=%s", device->udi));
+
+	/* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
+
+	/* however, the world can stop, mark this addon as ready 
+	 * (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
+	 */
+	if (hal_device_inc_num_ready_addons (device)) {
+		if (hal_device_are_all_addons_ready (device)) {
+			manager_send_signal_device_added (device);
+		}
+	}
+}
+
+
+
+
 static void
 gdl_store_changed (HalDeviceStore *store, HalDevice *device,
 		   gboolean is_added, gpointer user_data)
@@ -84,29 +107,38 @@ gdl_store_changed (HalDeviceStore *store
 
 		if ((addons = hal_device_property_get_strlist (device, "info.addons")) != NULL) {
 			GSList *i;
-			
+
 			for (i = addons; i != NULL; i = g_slist_next (i)) {
 				const gchar *command_line;
 				gchar *extra_env[2] = {"HALD_ACTION=addon", NULL};
 
 				command_line = (const gchar *) i->data;
-				hald_runner_start (device, command_line, extra_env);
-
-				HAL_INFO (("Started addon %s for udi %s", 
-				           command_line, hal_device_get_udi(device)));
+				if (hald_runner_start(device, command_line, extra_env, addon_terminated, NULL, NULL)) {
+					HAL_INFO (("Started addon %s for udi %s", 
+						   command_line, hal_device_get_udi(device)));
+					hal_device_inc_num_addons (device);
+				} else {
+					HAL_ERROR (("Cannot start addon %s for udi %s", 
+						    command_line, hal_device_get_udi(device)));
+				}
 			}
 		}
 	} else {
 		HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
-    hald_runner_kill_device(device);
+		hald_runner_kill_device(device);
 	}
 
 	/*hal_device_print (device);*/
 
-	if (is_added)
-		manager_send_signal_device_added (device);
-	else
-		manager_send_signal_device_removed (device);
+	if (is_added) {
+		if (hal_device_are_all_addons_ready (device)) {
+			manager_send_signal_device_added (device);
+		}
+	} else {
+		if (hal_device_are_all_addons_ready (device)) {
+			manager_send_signal_device_removed (device);
+		}
+	}
 }
 
 static void
@@ -114,7 +146,9 @@ gdl_property_changed (HalDeviceStore *st
 		      const char *key, gboolean added, gboolean removed,
 		      gpointer user_data)
 {
-	device_send_signal_property_modified (device, key, removed, added);
+	if (hal_device_are_all_addons_ready (device)) {
+		device_send_signal_property_modified (device, key, removed, added);
+	}
 
 	/* only execute the callouts if the property _changed_ */
 	if (added == FALSE && removed == FALSE)
@@ -125,7 +159,9 @@ static void
 gdl_capability_added (HalDeviceStore *store, HalDevice *device,
 		      const char *capability, gpointer user_data)
 {
-	manager_send_signal_new_capability (device, capability);
+	if (hal_device_are_all_addons_ready (device)) {
+		manager_send_signal_new_capability (device, capability);
+	}
 	/*hal_callout_capability (device, capability, TRUE)*/;
 }
 
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index 3e270af..a367f72 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -2505,6 +2505,70 @@ device_claim_interface (DBusConnection *
 }
 
 
+
+static DBusHandlerResult
+addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
+{
+	const char *udi;
+	HalDevice *device;
+	DBusMessageIter iter;
+	DBusMessage *reply;
+	DBusError error;
+	const char *interface_name;
+	const char *introspection_xml;
+	dbus_bool_t res;
+	
+	HAL_TRACE (("entering"));
+
+	udi = dbus_message_get_path (message);
+
+	if (!local_interface) {
+		raise_permission_denied (connection, message, "AddonIsReady: only allowed for helpers");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	HAL_DEBUG (("udi=%s", udi));
+
+	dbus_error_init (&error);
+	if (!dbus_message_get_args (message, &error,
+				    DBUS_TYPE_INVALID)) {
+		raise_syntax (connection, message, "AddonIsReady");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	device = hal_device_store_find (hald_get_gdl (), udi);
+	if (device == NULL)
+		device = hal_device_store_find (hald_get_tdl (), udi);
+
+	if (device == NULL) {
+		raise_no_such_device (connection, message, udi);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (hal_device_inc_num_ready_addons (device)) {
+		if (hal_device_are_all_addons_ready (device)) {
+			manager_send_signal_device_added (device);
+		}
+	}
+
+	res = TRUE;
+
+	HAL_INFO (("AddonIsReady on udi '%s'", udi));
+
+	reply = dbus_message_new_method_return (message);
+	if (reply == NULL)
+		DIE (("No memory"));
+	dbus_message_iter_init_append (reply, &iter);
+	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
+
+	if (!dbus_connection_send (connection, reply, NULL))
+		DIE (("No memory"));
+
+	dbus_message_unref (reply);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+
 /*
  * Create new device in tdl. Return temporary udi.
  */
@@ -3331,6 +3395,7 @@ do_introspect (DBusConnection  *connecti
 				       "    <method name=\"EmitCondition\">\n"
 				       "      <arg name=\"condition_name\" direction=\"in\" type=\"s\"/>\n"
 				       "      <arg name=\"condition_details\" direction=\"in\" type=\"s\"/>\n"
+				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
 				       "    </method>\n"
 
 				       "    <method name=\"Rescan\">\n"
@@ -3343,6 +3408,11 @@ do_introspect (DBusConnection  *connecti
 				       "    <method name=\"ClaimInterface\">\n"
 				       "      <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
 				       "      <arg name=\"introspection_xml\" direction=\"in\" type=\"s\"/>\n"
+				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
+				       "    </method>\n"
+
+				       "    <method name=\"AddonIsReady\">\n"
+				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
 				       "    </method>\n"
 
 				       "  </interface>\n");
@@ -3666,6 +3736,10 @@ hald_dbus_filter_handle_methods (DBusCon
 		return device_release_interface (connection, message, local_interface);
 #endif
 	} else if (dbus_message_is_method_call (message,
+						"org.freedesktop.Hal.Device",
+						"AddonIsReady")) {
+		return addon_is_ready (connection, message, local_interface);
+	} else if (dbus_message_is_method_call (message,
 						"org.freedesktop.DBus.Introspectable",
 						"Introspect")) {
 		return do_introspect (connection, message, local_interface);
diff --git a/hald/hald_runner.c b/hald/hald_runner.c
index 6a259ff..4fa7b44 100644
--- a/hald/hald_runner.c
+++ b/hald/hald_runner.c
@@ -51,17 +51,117 @@ typedef struct {
 
 static DBusConnection *runner_connection = NULL;
 
+typedef struct
+{
+	GPid pid;
+	HalDevice *device;
+	HalRunTerminatedCB cb;
+	gpointer data1;
+	gpointer data2;
+} RunningProcess;
+
+/* mapping from PID to RunningProcess */
+static GHashTable *running_processes;
+
+static gboolean
+rprd_foreach (gpointer key,
+	      gpointer value,
+	      gpointer user_data)
+{
+	gboolean remove;
+	RunningProcess *rp = value;
+	HalDevice *device = user_data;
+
+	if (rp->device == device) {
+		remove = TRUE;
+		g_free (rp);
+	}
+
+	return remove;
+}
+
+static void
+running_processes_remove_device (HalDevice *device)
+{
+	g_hash_table_foreach_remove (running_processes, rprd_foreach, device);
+}
+
+void
+runner_device_finalized (HalDevice *device)
+{
+	running_processes_remove_device (device);
+}
+
+
+static DBusHandlerResult 
+runner_server_message_handler (DBusConnection *connection, 
+			       DBusMessage *message, 
+			       void *user_data)
+{
+
+	/*HAL_INFO (("runner_server_message_handler: destination=%s obj_path=%s interface=%s method=%s", 
+		   dbus_message_get_destination (message), 
+		   dbus_message_get_path (message), 
+		   dbus_message_get_interface (message),
+		   dbus_message_get_member (message)));*/
+
+	if (dbus_message_is_signal (message, 
+				    "org.freedesktop.HalRunner", 
+				    "StartedProcessExited")) {
+		GPid pid;
+		DBusError error;
+		dbus_error_init (&error);
+		if (dbus_message_get_args (message, &error,
+				   DBUS_TYPE_INT64, &pid,
+				   DBUS_TYPE_INVALID)) {
+			RunningProcess *rp;
+
+			/*HAL_INFO (("Previously started process with pid %d exited", pid));*/
+
+			rp = g_hash_table_lookup (running_processes, (gpointer) pid);
+			if (rp != NULL) {
+				rp->cb (rp->device, 0, 0, NULL, rp->data1, rp->data2);
+				g_hash_table_remove (running_processes, (gpointer) pid);
+				g_free (rp);
+			}
+		}
+		
+	}
+
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+runner_server_unregister_handler (DBusConnection *connection, void *user_data)
+{
+	HAL_INFO (("unregistered"));
+}
+
+
 static void 
 handle_connection(DBusServer *server,
                   DBusConnection *new_connection,
-                  void *data) {
+                  void *data)
+{
 
-  if (runner_connection == NULL) {
-    runner_connection = new_connection;
-    dbus_connection_ref (new_connection);
-    dbus_connection_setup_with_g_main (new_connection, NULL);
-    /* dbus_server_unref(server); */
-  }
+	if (runner_connection == NULL) {
+		DBusObjectPathVTable vtable = { &runner_server_unregister_handler, 
+						&runner_server_message_handler, 
+						NULL, NULL, NULL, NULL};
+		
+		runner_connection = new_connection;
+		dbus_connection_ref (new_connection);
+		dbus_connection_setup_with_g_main (new_connection, NULL);
+
+		dbus_connection_register_fallback (new_connection, 
+						   "/org/freedesktop",
+						   &vtable,
+						   NULL);
+
+		/* dbus_server_unref(server); */
+
+	}
 }
 
 static void
@@ -81,6 +181,8 @@ hald_runner_start_runner(void)
   char *env[] =  { NULL, NULL, NULL, NULL};
   const char *hald_runner_path;
 
+  running_processes = g_hash_table_new (g_direct_hash, g_direct_equal);
+
   dbus_error_init(&err);
   server = dbus_server_listen(DBUS_SERVER_ADDRESS, &err);
   if (server == NULL) {
@@ -91,6 +193,8 @@ hald_runner_start_runner(void)
   dbus_server_setup_with_g_main(server, NULL);
   dbus_server_set_new_connection_function(server, handle_connection, 
                                           NULL, NULL);
+
+
   argv[0] = "hald-runner";
   env[0] = g_strdup_printf("HALD_RUNNER_DBUS_ADDRESS=%s",
              dbus_server_get_address(server));
@@ -255,8 +359,9 @@ add_first_part(DBusMessageIter *iter, Ha
 
 /* Start a helper, returns true on a successfull start */
 gboolean
-hald_runner_start(HalDevice *device,
-                      const gchar *command_line, char **extra_env) {
+hald_runner_start (HalDevice *device, const gchar *command_line, char **extra_env, 
+		   HalRunTerminatedCB cb, gpointer data1, gpointer data2)
+{
   DBusMessage *msg, *reply;
   DBusError err;
   DBusMessageIter iter;
@@ -280,6 +385,28 @@ hald_runner_start(HalDevice *device,
   if (reply) {
     gboolean ret = 
       (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN);
+
+    if (ret) {
+	dbus_int64_t pid_from_runner;
+	if (dbus_message_get_args (reply, &err,
+				   DBUS_TYPE_INT64, &pid_from_runner,
+				   DBUS_TYPE_INVALID)) {
+		if (cb != NULL) {
+			RunningProcess *rp;
+			rp = g_new0 (RunningProcess, 1);
+			rp->pid = (GPid) pid_from_runner;
+			rp->cb = cb;
+			rp->device = device;
+			rp->data1 = data1;
+			rp->data2 = data2;
+
+			g_hash_table_insert (running_processes, (gpointer) rp->pid, rp);
+		}
+	} else {
+	  HAL_ERROR (("Error extracting out_pid from runner's Start()"));
+	}
+    }
+
     dbus_message_unref(reply);
     dbus_message_unref(msg);
     return ret;
@@ -402,12 +529,16 @@ hald_runner_run(HalDevice *device,
                              "", FALSE, timeout, cb, data1, data2);
 }
 
+
+
 void
 hald_runner_kill_device(HalDevice *device) {
   DBusMessage *msg, *reply;
   DBusError err;
   DBusMessageIter iter;
   const char *udi;
+
+  running_processes_remove_device (device);
   
   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                              "/org/freedesktop/HalRunner",
@@ -434,6 +565,9 @@ void
 hald_runner_kill_all(HalDevice *device) {
   DBusMessage *msg, *reply;
   DBusError err;
+
+  running_processes_remove_device (device);
+
   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                              "/org/freedesktop/HalRunner",
                              "org.freedesktop.HalRunner",
diff --git a/hald/hald_runner.h b/hald/hald_runner.h
index a098ec4..ca05573 100644
--- a/hald/hald_runner.h
+++ b/hald/hald_runner.h
@@ -49,10 +49,13 @@ typedef void (*HalRunTerminatedCB) (HalD
 gboolean
 hald_runner_start_runner(void);
 
-/* Start a helper, returns true on a successfull start */
+/* Start a helper, returns true on a successfull start. 
+ * cb will be called on abnormal or premature termination
+ * only 
+ */
 gboolean
-hald_runner_start(HalDevice *device, const gchar *command_line, 
-                  char **extra_env);
+hald_runner_start (HalDevice *device, const gchar *command_line, char **extra_env, 
+		   HalRunTerminatedCB cb, gpointer data1, gpointer data2);
 
 /* Run a helper program using the commandline, with input as infomation on
  * stdin */
@@ -73,4 +76,7 @@ hald_runner_run_method(HalDevice *device
 void hald_runner_kill_device(HalDevice *device);
 void hald_runner_kill_all();
 
+/* called by the core to tell the runner a device was finalized */
+void runner_device_finalized (HalDevice *device);
+
 #endif 
diff --git a/hald/linux/addons/addon-acpi-buttons-toshiba.c b/hald/linux/addons/addon-acpi-buttons-toshiba.c
index 7252759..eb833ef 100644
--- a/hald/linux/addons/addon-acpi-buttons-toshiba.c
+++ b/hald/linux/addons/addon-acpi-buttons-toshiba.c
@@ -164,6 +164,11 @@ main (int argc, char **argv)
 		return 1;
 	}
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+		return 1;
+	}
+
 	/* Check for Toshiba ACPI interface /proc/acpi/toshiba/keys */
 	fp = fopen (TOSHIBA_ACPI_KEYS, "r+");
 	if (!fp) {
diff --git a/hald/linux/addons/addon-acpi.c b/hald/linux/addons/addon-acpi.c
index 4b19321..ac84a9e 100644
--- a/hald/linux/addons/addon-acpi.c
+++ b/hald/linux/addons/addon-acpi.c
@@ -170,12 +170,16 @@ main (int argc, char **argv)
 	setup_logger ();
 
 	dbus_error_init (&error);
-
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
 		HAL_ERROR (("Unable to initialise libhal context: %s", error.message));
 		return 1;
 	}
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) {
+		return 1;
+	}
+
 #ifdef ACPI_PROC
 	/* If we can connect directly to the kernel then do so. */
 	eventfp = acpi_get_event_fp_kernel ();
diff --git a/hald/linux/addons/addon-cpufreq.c b/hald/linux/addons/addon-cpufreq.c
index 92d1767..fbc30ef 100644
--- a/hald/linux/addons/addon-cpufreq.c
+++ b/hald/linux/addons/addon-cpufreq.c
@@ -1090,6 +1090,12 @@ gboolean dbus_init(void)
 		goto Error;
 	}
 
+	dbus_error_init (&dbus_error);
+	if (!libhal_device_addon_is_ready (halctx, udi, &dbus_error)) {
+		goto Error;
+	}
+
+
 	if (!libhal_device_claim_interface(halctx, udi,
 		"org.freedesktop.Hal.Device.CPUFreq", 
 		"    <method name=\"SetCPUFreqGovernor\">\n"
diff --git a/hald/linux/addons/addon-hid-ups.c b/hald/linux/addons/addon-hid-ups.c
index c073eb7..698d893 100644
--- a/hald/linux/addons/addon-hid-ups.c
+++ b/hald/linux/addons/addon-hid-ups.c
@@ -142,7 +142,6 @@ ups_get_static (LibHalContext *ctx, cons
 		goto out;
 	}
 
-
 	/* set to failure */
 	ret = FALSE;
 
@@ -326,9 +325,13 @@ main (int argc, char *argv[])
 	if (!ups_get_static (ctx, udi, fd, &prop_remaining, &prop_runtime, &prop_charging, &prop_discharging))
 		goto out;
 
-
 	hal_set_proc_title ("hald-addon-hid-ups: listening on %s", device_file);
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+		goto out;
+	}
+
 	FD_ZERO(&fdset);
 	while (1) {
 		FD_SET(fd, &fdset);
@@ -336,7 +339,6 @@ main (int argc, char *argv[])
 
 		
 		if (rd > 0) {
-			DBusError error;
 			LibHalChangeSet *cs;
 
 			rd = read(fd, ev, sizeof(ev));
diff --git a/hald/linux/addons/addon-keyboard.c b/hald/linux/addons/addon-keyboard.c
index a054ac9..13f4fd5 100644
--- a/hald/linux/addons/addon-keyboard.c
+++ b/hald/linux/addons/addon-keyboard.c
@@ -200,6 +200,12 @@ main (int argc, char **argv)
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
                 goto out;
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+		goto out;
+	}
+
+
 	eventfp = fopen(device_file, "r");	
 
 	if (!eventfp)
diff --git a/hald/linux/addons/addon-macbookpro-backlight.c b/hald/linux/addons/addon-macbookpro-backlight.c
index f25a555..53dbb90 100644
--- a/hald/linux/addons/addon-macbookpro-backlight.c
+++ b/hald/linux/addons/addon-macbookpro-backlight.c
@@ -422,6 +422,12 @@ main (int argc, char *argv[])
 		return -3;
 	}
 
+	dbus_error_init (&err);
+	if (!libhal_device_addon_is_ready (halctx, udi, &err)) {
+		return -4;
+	}
+
+
 	conn = libhal_ctx_get_dbus_connection (halctx);
 	dbus_connection_setup_with_g_main (conn, NULL);
 
diff --git a/hald/linux/addons/addon-pmu.c b/hald/linux/addons/addon-pmu.c
index 68b59fe..f292460 100644
--- a/hald/linux/addons/addon-pmu.c
+++ b/hald/linux/addons/addon-pmu.c
@@ -66,6 +66,12 @@ main (int argc, char *argv[])
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
 		goto out;
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+		goto out;
+	}
+
+
 	/* initial state */
 	if ((strstate = getenv ("HAL_PROP_BUTTON_STATE_VALUE")) == NULL) {
 		HAL_ERROR (("Cannot get HAL_PROP_BUTTON_STATE_VALUE"));
diff --git a/hald/linux/addons/addon-storage.c b/hald/linux/addons/addon-storage.c
index 5d848c5..22247cf 100644
--- a/hald/linux/addons/addon-storage.c
+++ b/hald/linux/addons/addon-storage.c
@@ -302,6 +302,11 @@ main (int argc, char *argv[])
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
 		goto out;
 
+	dbus_error_init (&error);
+	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+		goto out;
+	}
+
 	HAL_DEBUG (("**************************************************"));
 	HAL_DEBUG (("Doing addon-storage for %s (bus %s) (drive_type %s) (udi %s)", device_file, bus, drive_type, udi));
 	HAL_DEBUG (("**************************************************"));
diff --git a/hald/linux/addons/addon-usb-csr.c b/hald/linux/addons/addon-usb-csr.c
index cd1747d..a761108 100644
--- a/hald/linux/addons/addon-usb-csr.c
+++ b/hald/linux/addons/addon-usb-csr.c
@@ -281,6 +281,7 @@ main (int argc, char *argv[])
 		return -3;
 	}
 
+
 	/* update_properties */
 	dbus_error_init (&err);
 	libhal_device_set_property_bool (halctx, device_udi, 
@@ -315,6 +316,11 @@ main (int argc, char *argv[])
 	dbus_error_init (&err);
 	libhal_device_add_capability (halctx, device_udi, "battery", &err);
 
+	dbus_error_init (&err);
+	if (!libhal_device_addon_is_ready (halctx, device_udi, &err)) {
+		return -4;
+	}
+
 	hal_set_proc_title ("hald-addon-usb-csr: listening on '%s'", 
 			    libhal_device_get_property_string(halctx, device_udi,
 							      "info.product", &err));
diff --git a/libhal/libhal.c b/libhal/libhal.c
index 0627aaa..a577829 100644
--- a/libhal/libhal.c
+++ b/libhal/libhal.c
@@ -3379,6 +3379,70 @@ dbus_bool_t libhal_device_emit_condition
 }
 
 /** 
+ * libhal_device_addon_is_ready:
+ * @ctx: the context for the connection to hald
+ * @udi: the Unique Device Id
+ * @error: pointer to an initialized dbus error object for returning errors or NULL
+ *
+ * HAL addon's must call this method when they are done initializing the device object. The HAL
+ * daemon will wait for all addon's to call this.
+ *
+ * Can only be used from hald helpers.
+ *
+ * Returns: TRUE if the HAL daemon received the message, FALSE otherwise
+ */
+dbus_bool_t
+libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error)
+{
+	DBusMessage *message;
+	DBusMessageIter iter;
+	DBusMessageIter reply_iter;
+	DBusMessage *reply;
+	dbus_bool_t result;
+
+	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+
+	message = dbus_message_new_method_call ("org.freedesktop.Hal",
+						udi,
+						"org.freedesktop.Hal.Device",
+						"AddonIsReady");
+
+	if (message == NULL) {
+		fprintf (stderr,
+			 "%s %d : Couldn't allocate D-BUS message\n",
+			 __FILE__, __LINE__);
+		return FALSE;
+	}
+
+	dbus_message_iter_init_append (message, &iter);
+	
+	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+							   message, -1,
+							   error);
+
+	if (dbus_error_is_set (error)) {
+		dbus_message_unref (message);
+		return FALSE;
+	}
+
+	dbus_message_unref (message);
+
+	if (reply == NULL)
+		return FALSE;
+
+	dbus_message_iter_init (reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
+		dbus_message_unref (message);
+		dbus_message_unref (reply);
+		return FALSE;
+	}
+	dbus_message_iter_get_basic (&reply_iter, &result);
+
+	dbus_message_unref (reply);
+	return result;	
+}
+
+/** 
  * libhal_device_claim_interface:
  * @ctx: the context for the connection to hald
  * @udi: the Unique Device Id
diff --git a/libhal/libhal.h b/libhal/libhal.h
index ab00e57..9962da1 100644
--- a/libhal/libhal.h
+++ b/libhal/libhal.h
@@ -593,6 +593,9 @@ dbus_bool_t libhal_device_claim_interfac
 					   const char *introspection_xml,
 					   DBusError *error);
 
+/* hald waits for all addons to call this function before announcing the addon (for hald helpers only) */
+dbus_bool_t libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error);
+
 
 #if defined(__cplusplus)
 }
diff --git a/partutil/.gitignore b/partutil/.gitignore
new file mode 100644
index 0000000..0ec65bf
--- /dev/null
+++ b/partutil/.gitignore
@@ -0,0 +1,8 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.la
+*.lo
+*.o
+*~
diff --git a/tools/.gitignore b/tools/.gitignore
index 1df1a5c..94316c8 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -19,5 +19,6 @@ hal-storage-cleanup-all-mountpoints
 hal-storage-cleanup-mountpoint
 hal-storage-eject
 hal-storage-unmount
+hal-storage-closetray
 *.o
 *~
diff-tree ed71e4e6769b8f359f7626f788a38db5f63faca8 (from 989e1bcc472cd7c130ae828e7d5d2ca81ee300db)
Author: David Zeuthen <davidz at redhat.com>
Date:   Sun Sep 10 13:49:32 2006 -0400

    make addon-hip-ups use LibHalChangeSet
    
    Also put some brains into addon-hid-ups so it only sets properties if
    they are changed. Fix libhal_device_commit_changeset do nothing
    if the changeset is empty. Should reduce load when having a USB UPS.

diff --git a/doc/api/tmpl/hal-unused.sgml b/doc/api/tmpl/hal-unused.sgml
index 6fb25b0..4f9d772 100644
--- a/doc/api/tmpl/hal-unused.sgml
+++ b/doc/api/tmpl/hal-unused.sgml
@@ -286,30 +286,6 @@ logging
 main
 
 
-<!-- ##### SECTION ./tmpl/shared.sgml:Long_Description ##### -->
-<para>
-
-</para>
-
-
-<!-- ##### SECTION ./tmpl/shared.sgml:See_Also ##### -->
-<para>
-
-</para>
-
-
-<!-- ##### SECTION ./tmpl/shared.sgml:Short_Description ##### -->
-
-
-
-<!-- ##### SECTION ./tmpl/shared.sgml:Stability_Level ##### -->
-
-
-
-<!-- ##### SECTION ./tmpl/shared.sgml:Title ##### -->
-shared
-
-
 <!-- ##### SECTION ./tmpl/sysfs.sgml:Long_Description ##### -->
 <para>
 
@@ -1458,6 +1434,22 @@ sysfs
 @udi: 
 @Returns: 
 
+<!-- ##### FUNCTION libhal_volume_get_msdos_part_table_size ##### -->
+<para>
+
+</para>
+
+ at volume: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_get_msdos_part_table_start ##### -->
+<para>
+
+</para>
+
+ at volume: 
+ at Returns: 
+
 <!-- ##### FUNCTION libhal_volume_policy_compute_display_name ##### -->
 <para>
 
@@ -1537,6 +1529,22 @@ sysfs
 @target_mount_point: 
 @Returns: 
 
+<!-- ##### FUNCTION libhal_volume_should_ignore ##### -->
+<para>
+
+</para>
+
+ at volume: 
+ at Returns: 
+
+<!-- ##### FUNCTION logger_forward_debug ##### -->
+<para>
+
+</para>
+
+ at format: 
+ at Varargs: 
+
 <!-- ##### FUNCTION lstat ##### -->
 <para>
 
@@ -1599,6 +1607,12 @@ sysfs
 @namespace: 
 @Returns: 
 
+<!-- ##### FUNCTION setup_logger ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### FUNCTION visit_class_device_block ##### -->
 <para>
 
diff --git a/doc/api/tmpl/libhal-storage.sgml b/doc/api/tmpl/libhal-storage.sgml
index c99e3c2..deb2bf8 100644
--- a/doc/api/tmpl/libhal-storage.sgml
+++ b/doc/api/tmpl/libhal-storage.sgml
@@ -661,34 +661,6 @@ libhal-storage
 
 </para>
 
- at volume: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_get_msdos_part_table_start ##### -->
-<para>
-
-</para>
-
- at volume: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_get_msdos_part_table_size ##### -->
-<para>
-
-</para>
-
- at volume: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_should_ignore ##### -->
-<para>
-
-</para>
-
- at volume: 
 @Returns: 
 
 
diff --git a/doc/api/tmpl/logger.sgml b/doc/api/tmpl/logger.sgml
index ee46b8c..2878b23 100644
--- a/doc/api/tmpl/logger.sgml
+++ b/doc/api/tmpl/logger.sgml
@@ -37,15 +37,6 @@ logger
 @Varargs: 
 
 
-<!-- ##### FUNCTION logger_forward_debug ##### -->
-<para>
-
-</para>
-
- at format: 
- at Varargs: 
-
-
 <!-- ##### FUNCTION logger_enable ##### -->
 <para>
 
@@ -74,13 +65,6 @@ logger
 
 
 
-<!-- ##### FUNCTION setup_logger ##### -->
-<para>
-
-</para>
-
-
-
 <!-- ##### MACRO HAL_TRACE ##### -->
 <para>
 
diff --git a/doc/api/tmpl/util.sgml b/doc/api/tmpl/util.sgml
index a61ab35..d2e2321 100644
--- a/doc/api/tmpl/util.sgml
+++ b/doc/api/tmpl/util.sgml
@@ -38,6 +38,32 @@ util
 
 
 
+<!-- ##### FUNCTION util_compute_time_remaining ##### -->
+<para>
+
+</para>
+
+ at id: 
+ at chargeRate: 
+ at chargeLevel: 
+ at chargeLastFull: 
+ at isDischarging: 
+ at isCharging: 
+ at guessChargeRate: 
+ at Returns: 
+
+
+<!-- ##### FUNCTION util_compute_percentage_charge ##### -->
+<para>
+
+</para>
+
+ at id: 
+ at chargeLevel: 
+ at chargeLastFull: 
+ at Returns: 
+
+
 <!-- ##### FUNCTION hal_util_remove_trailing_slash ##### -->
 <para>
 
diff --git a/hald/linux/addons/addon-hid-ups.c b/hald/linux/addons/addon-hid-ups.c
index 64677d8..c073eb7 100644
--- a/hald/linux/addons/addon-hid-ups.c
+++ b/hald/linux/addons/addon-hid-ups.c
@@ -120,7 +120,11 @@ ups_get_string (int fd, int sindex)
 
 
 static dbus_bool_t
-ups_get_static (LibHalContext *ctx, const char *udi, int fd)
+ups_get_static (LibHalContext *ctx, const char *udi, int fd, 
+		dbus_int32_t *prop_remaining,
+		dbus_int32_t *prop_runtime,
+		dbus_bool_t *prop_charging,
+		dbus_bool_t *prop_discharging)
 {
 	int ret;
 	struct hiddev_report_info rinfo;
@@ -130,6 +134,14 @@ ups_get_static (LibHalContext *ctx, cons
 	unsigned int i, j;
 	char *type;
 	DBusError error;
+	LibHalChangeSet *cs;
+
+	cs = libhal_device_new_changeset (udi);
+	if (cs == NULL) {
+		HAL_ERROR (("Cannot initialize changeset"));
+		goto out;
+	}
+
 
 	/* set to failure */
 	ret = FALSE;
@@ -158,93 +170,95 @@ ups_get_static (LibHalContext *ctx, cons
 					ioctl (fd, HIDIOCGUCODE, &uref);
 					ioctl (fd, HIDIOCGUSAGE, &uref);
 
-					dbus_error_init (&error);
-
 					switch (uref.usage_code) {
 
 					case UPS_REMAINING_CAPACITY:
-						libhal_device_set_property_int (
-							ctx, udi, "battery.charge_level.current", uref.value, &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.charge_level.percentage", uref.value, &error);
-						libhal_device_set_property_string (
-							ctx, udi, "battery.charge_level.unit", "percent", &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.reporting.current", uref.value, &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.reporting.percentage", uref.value, &error);
-						libhal_device_set_property_string (
-							ctx, udi, "battery.reporting.unit", "percent", &error);
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.current", uref.value);
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.percentage", uref.value);
+						libhal_changeset_set_property_string (
+							cs, "battery.charge_level.unit", "percent");
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.current", uref.value);
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.percentage", uref.value);
+						libhal_changeset_set_property_string (
+							cs, "battery.reporting.unit", "percent");
+						*prop_remaining = uref.value;
 						break;
 
 					case UPS_RUNTIME_TO_EMPTY:
-						libhal_device_set_property_int (
-							ctx, udi, "battery.remaining_time", uref.value, &error);
+						libhal_changeset_set_property_int (
+							cs, "battery.remaining_time", uref.value);
+						*prop_runtime = uref.value;
 						break;
 
 					case UPS_CHARGING:
-						libhal_device_set_property_bool (
-							ctx, udi, "battery.rechargeable.is_charging", uref.value != 0, &error);
+						libhal_changeset_set_property_bool (
+							cs, "battery.rechargeable.is_charging", uref.value != 0);
+						*prop_charging = uref.value != 0;
 						break;
 
 					case UPS_DISCHARGING:
-						libhal_device_set_property_bool (
-							ctx, udi, "battery.rechargeable.is_discharging", uref.value != 0, &error);
+						libhal_changeset_set_property_bool (
+							cs, "battery.rechargeable.is_discharging", uref.value != 0);
+						*prop_discharging = uref.value != 0;
 						break;
 
 					case UPS_BATTERYPRESENT:
-						libhal_device_set_property_bool (
-							ctx, udi, "battery.present", uref.value != 0, &error);
+						libhal_changeset_set_property_bool (
+							cs, "battery.present", uref.value != 0);
 						break;
 
 					case UPS_DEVICENAME:
-						libhal_device_set_property_string (
-							ctx, udi, "foo", 
-							ups_get_string (fd, uref.value), &error);
+						libhal_changeset_set_property_string (
+							cs, "foo", 
+							ups_get_string (fd, uref.value));
 						break;
 
 					case UPS_CHEMISTRY:
 						type = ups_get_string (fd, uref.value);
-						libhal_device_set_property_string (
-							ctx, udi, "battery.reporting.technology", 
-							type, &error);
-						libhal_device_set_property_string (
-							ctx, udi, "battery.technology", 
-							util_get_battery_technology (type), &error);
+						libhal_changeset_set_property_string (
+							cs, "battery.reporting.technology", 
+							type);
+						libhal_changeset_set_property_string (
+							cs, "battery.technology", 
+							util_get_battery_technology (type));
 						break;
 
 					case UPS_RECHARGEABLE:
-						libhal_device_set_property_bool (
-							ctx, udi, "battery.is_rechargeable", uref.value != 0, &error);
+						libhal_changeset_set_property_bool (
+							cs, "battery.is_rechargeable", uref.value != 0);
 						break;
 
 					case UPS_OEMINFORMATION:
-						libhal_device_set_property_string (
-							ctx, udi, "battery.vendor", 
-							ups_get_string (fd, uref.value), &error);
+						libhal_changeset_set_property_string (
+							cs, "battery.vendor", 
+							ups_get_string (fd, uref.value));
 						break;
 
 					case UPS_PRODUCT:
-						libhal_device_set_property_string (
-							ctx, udi, "battery.model", 
-							ups_get_string (fd, uref.value), &error);
+						libhal_changeset_set_property_string (
+							cs, "battery.model", 
+							ups_get_string (fd, uref.value));
 						break;
 
 					case UPS_SERIALNUMBER:
-						libhal_device_set_property_string (
-							ctx, udi, "battery.serial", 
-							ups_get_string (fd, uref.value), &error);
+						libhal_changeset_set_property_string (
+							cs, "battery.serial", 
+							ups_get_string (fd, uref.value));
 						break;
 
 					case UPS_DESIGNCAPACITY:
-						libhal_device_set_property_int (
-							ctx, udi, "battery.charge_level.design", uref.value, &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.charge_level.last_full", uref.value, &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.reporting.design", uref.value, &error);
-						libhal_device_set_property_int (
-							ctx, udi, "battery.reporting.last_full", uref.value, &error);
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.design", uref.value);
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.last_full", uref.value);
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.design", uref.value);
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.last_full", uref.value);
 						break;
 
 					default:
@@ -256,8 +270,14 @@ ups_get_static (LibHalContext *ctx, cons
 		}
 	}
 
-	libhal_device_set_property_bool (ctx, udi, "battery.present", TRUE, &error);
-	libhal_device_set_property_string (ctx, udi, "battery.type", "ups", &error);
+	libhal_changeset_set_property_bool (cs, "battery.present", TRUE);
+	libhal_changeset_set_property_string (cs, "battery.type", "ups");
+
+	dbus_error_init (&error);
+	libhal_device_commit_changeset (ctx, cs, &error);
+	libhal_device_free_changeset (cs);
+
+	dbus_error_init (&error);
 	libhal_device_add_capability (ctx, udi, "battery", &error);
 
 	ret = TRUE;
@@ -278,6 +298,10 @@ main (int argc, char *argv[])
 	fd_set fdset;
 	struct hiddev_event ev[64];
 	int rd;
+	dbus_int32_t prop_remaining = 0;
+	dbus_int32_t prop_runtime = 0;
+	dbus_bool_t prop_charging = FALSE;
+	dbus_bool_t prop_discharging = FALSE;
 
 	hal_set_proc_title_init (argc, argv);
 
@@ -299,58 +323,84 @@ main (int argc, char *argv[])
 	if (fd < 0)
 		goto out;
 
-	if (!ups_get_static (ctx, udi, fd))
+	if (!ups_get_static (ctx, udi, fd, &prop_remaining, &prop_runtime, &prop_charging, &prop_discharging))
 		goto out;
 
+
 	hal_set_proc_title ("hald-addon-hid-ups: listening on %s", device_file);
 
 	FD_ZERO(&fdset);
 	while (1) {
 		FD_SET(fd, &fdset);
 		rd = select(fd+1, &fdset, NULL, NULL, NULL);
+
 		
 		if (rd > 0) {
+			DBusError error;
+			LibHalChangeSet *cs;
+
 			rd = read(fd, ev, sizeof(ev));
 			if (rd < (int) sizeof(ev[0])) {
 				close(fd);
 				goto out;
 			}
 
-			for (i = 0; i < rd / sizeof(ev[0]); i++) {
-				DBusError error;
-				
-				dbus_error_init (&error);
+			cs = libhal_device_new_changeset (udi);
+			if (cs == NULL) {
+				HAL_ERROR (("Cannot initialize changeset"));
+				goto out;
+			}
+
+			for (i = 0; i < rd / sizeof(ev[0]); i++) {				
 				switch (ev[i].hid) {
 				case UPS_REMAINING_CAPACITY:
-					libhal_device_set_property_int (
-						ctx, udi, "battery.charge_level.current", ev[i].value, &error);
-					libhal_device_set_property_int (
-						ctx, udi, "battery.charge_level.percentage", ev[i].value, &error);
-					libhal_device_set_property_int (
-						ctx, udi, "battery.reporting.current", ev[i].value, &error);
-					libhal_device_set_property_int (
-						ctx, udi, "battery.reporting.percentage", ev[i].value, &error);
+					if (ev[i].value != prop_remaining) {
+						prop_remaining = ev[i].value;
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.current", ev[i].value);
+						libhal_changeset_set_property_int (
+							cs, "battery.charge_level.percentage", ev[i].value);
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.current", ev[i].value);
+						libhal_changeset_set_property_int (
+							cs, "battery.reporting.percentage", ev[i].value);
+					}
 					break;
 					
 				case UPS_RUNTIME_TO_EMPTY:
-					libhal_device_set_property_int (
-						ctx, udi, "battery.remaining_time", ev[i].value, &error);
+					if (ev[i].value != prop_runtime) {
+						prop_runtime = ev[i].value;
+						libhal_changeset_set_property_int (
+							cs, "battery.remaining_time", ev[i].value);
+					}
 					break;
 					
 				case UPS_CHARGING:
-					libhal_device_set_property_bool (
-						ctx, udi, "battery.rechargeable.is_charging", ev[i].value != 0, &error);
+					if ((ev[i].value != 0) != prop_charging) {
+						prop_charging = (ev[i].value != 0);
+						libhal_changeset_set_property_bool (
+							cs, "battery.rechargeable.is_charging", ev[i].value != 0);
+					}
 					break;
 					
 				case UPS_DISCHARGING:
-					libhal_device_set_property_bool (
-						ctx, udi, "battery.rechargeable.is_discharging", ev[i].value != 0, &error);
+					if ((ev[i].value != 0) != prop_discharging) {
+						prop_discharging = (ev[i].value != 0);
+						libhal_changeset_set_property_bool (
+							cs, "battery.rechargeable.is_discharging", ev[i].value != 0);
+					}
 					break;
 					
 				default:
 					break;
 				}
 			}
+
+			dbus_error_init (&error);
+			/* NOTE: commit_changeset won't do IPC if set is empty */
+			libhal_device_commit_changeset (ctx, cs, &error);
+			libhal_device_free_changeset (cs);
+
 		}
 	}
 
diff --git a/libhal/libhal.c b/libhal/libhal.c
index ecc5df9..0627aaa 100644
--- a/libhal/libhal.c
+++ b/libhal/libhal.c
@@ -3773,6 +3773,10 @@ libhal_device_commit_changeset (LibHalCo
 
 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
 
+	if (changeset->head == NULL) {
+		return TRUE;
+	}
+
 	message = dbus_message_new_method_call ("org.freedesktop.Hal", changeset->udi,
 						"org.freedesktop.Hal.Device",
 						"SetMultipleProperties");


More information about the hal-commit mailing list