[packagekit] packagekit: Branch 'master' - 2 commits

Richard Hughes hughsient at kemper.freedesktop.org
Sun Sep 9 16:05:19 PDT 2007


 TODO                            |    4 
 libpackagekit/pk-task-monitor.c |   96 ++++++++
 libpackagekit/pk-task-monitor.h |    6 
 src/Makefile.am                 |    2 
 src/pk-backend-internal.h       |    6 
 src/pk-backend.c                |   56 ++++
 src/pk-engine.c                 |  462 ++++++++++++++++------------------------
 src/pk-engine.h                 |   13 +
 src/pk-interface.xml            |   17 +
 src/pk-job-list.c               |  357 ++++++++++++++++++++++++++++++
 src/pk-job-list.h               |   76 ++++++
 tools/add-error-enum.sh         |    2 
 tools/add-method.sh             |    4 
 13 files changed, 829 insertions(+), 272 deletions(-)

New commits:
diff-tree 09ebb9bad8573390a1d1c03408974060b725282f (from 168dccfeb1bb6fd5748c72b3e524ab7e4f0bf6c1)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 9 23:52:07 2007 +0100

    abstact out the job list and make the creation more robust

diff --git a/src/Makefile.am b/src/Makefile.am
index 5ecd794..2949a86 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,6 +46,8 @@ packagekitd_SOURCES =					\
 	pk-backend.h					\
 	pk-conf.c					\
 	pk-conf.h					\
+	pk-job-list.c					\
+	pk-job-list.h					\
 	pk-spawn.c					\
 	pk-spawn.h					\
 	pk-engine.h					\
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 8c4dd8c..e1bb191 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -46,6 +46,7 @@
 
 #include "pk-backend-internal.h"
 #include "pk-engine.h"
+#include "pk-job-list.h"
 #include "pk-marshal.h"
 
 static void     pk_engine_class_init	(PkEngineClass *klass);
@@ -53,16 +54,14 @@ static void     pk_engine_init		(PkEngin
 static void     pk_engine_finalize	(GObject       *object);
 
 #define PK_ENGINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_ENGINE, PkEnginePrivate))
-#define PK_ENGINE_JOB_LAST_COUNT_FILE		LOCALSTATEDIR "/run/PackageKit/job_count.dat"
 
 struct PkEnginePrivate
 {
-	GPtrArray		*array;
 	GTimer			*timer;
-	guint			 job_count;
 	PolKitContext		*pk_context;
 	DBusConnection		*connection;
 	gchar			*backend;
+	PkJobList		*job_list;
 };
 
 enum {
@@ -80,11 +79,6 @@ enum {
 	PK_ENGINE_LAST_SIGNAL
 };
 
-typedef struct {
-	guint		 job;
-	PkTask		*task;
-} PkEngineMap;
-
 static guint	     signals [PK_ENGINE_LAST_SIGNAL] = { 0, };
 
 G_DEFINE_TYPE (PkEngine, pk_engine, G_TYPE_OBJECT)
@@ -151,80 +145,6 @@ pk_engine_reset_timer (PkEngine *engine)
 }
 
 /**
- * pk_engine_create_job_list:
- **/
-static GArray *
-pk_engine_create_job_list (PkEngine *engine)
-{
-	guint i;
-	guint length;
-	GArray *job_list;
-	PkEngineMap *map;
-
-	g_return_val_if_fail (engine != NULL, FALSE);
-	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
-
-	/* create new list */
-	job_list = g_array_new (FALSE, FALSE, sizeof (guint));
-
-	/* find all the jobs in progress */
-	length = engine->priv->array->len;
-	for (i=0; i<length; i++) {
-		map = (PkEngineMap *) g_ptr_array_index (engine->priv->array, i);
-		job_list = g_array_append_val (job_list, map->job);
-	}
-	return job_list;
-}
-
-/**
- * pk_get_map_from_job:
- **/
-static PkEngineMap *
-pk_get_map_from_job (PkEngine *engine, guint job)
-{
-	guint i;
-	guint length;
-	PkEngineMap *map;
-
-	g_return_val_if_fail (engine != NULL, NULL);
-	g_return_val_if_fail (PK_IS_ENGINE (engine), NULL);
-
-	/* find the task with the job ID */
-	length = engine->priv->array->len;
-	for (i=0; i<length; i++) {
-		map = (PkEngineMap *) g_ptr_array_index (engine->priv->array, i);
-		if (map->job == job) {
-			return map;
-		}
-	}
-	return NULL;
-}
-
-/**
- * pk_get_map_from_task:
- **/
-static PkEngineMap *
-pk_get_map_from_task (PkEngine *engine, PkTask *task)
-{
-	guint i;
-	guint length;
-	PkEngineMap *map;
-
-	g_return_val_if_fail (engine != NULL, NULL);
-	g_return_val_if_fail (PK_IS_ENGINE (engine), NULL);
-
-	/* find the task with the job ID */
-	length = engine->priv->array->len;
-	for (i=0; i<length; i++) {
-		map = (PkEngineMap *) g_ptr_array_index (engine->priv->array, i);
-		if (map->task == task) {
-			return map;
-		}
-	}
-	return NULL;
-}
-
-/**
  * pk_engine_job_list_changed:
  **/
 static gboolean
@@ -235,7 +155,7 @@ pk_engine_job_list_changed (PkEngine *en
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	job_list = pk_engine_create_job_list (engine);
+	job_list = pk_job_list_get_array (engine->priv->job_list);
 
 	pk_debug ("emitting job-list-changed");
 	g_signal_emit (engine, signals [PK_ENGINE_JOB_LIST_CHANGED], 0, job_list);
@@ -249,21 +169,21 @@ pk_engine_job_list_changed (PkEngine *en
 static void
 pk_engine_job_status_changed_cb (PkTask *task, PkStatusEnum status, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	const gchar *status_text;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
 		status_text = pk_status_enum_to_text (status);
 
-	pk_debug ("emitting job-status-changed job:%i, '%s'", map->job, status_text);
-	g_signal_emit (engine, signals [PK_ENGINE_JOB_STATUS_CHANGED], 0, map->job, status_text);
+	pk_debug ("emitting job-status-changed job:%i, '%s'", item->job, status_text);
+	g_signal_emit (engine, signals [PK_ENGINE_JOB_STATUS_CHANGED], 0, item->job, status_text);
 	pk_engine_reset_timer (engine);
 }
 
@@ -273,18 +193,18 @@ pk_engine_job_status_changed_cb (PkTask 
 static void
 pk_engine_percentage_changed_cb (PkTask *task, guint percentage, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	pk_debug ("emitting percentage-changed job:%i %i", map->job, percentage);
-	g_signal_emit (engine, signals [PK_ENGINE_PERCENTAGE_CHANGED], 0, map->job, percentage);
+	pk_debug ("emitting percentage-changed job:%i %i", item->job, percentage);
+	g_signal_emit (engine, signals [PK_ENGINE_PERCENTAGE_CHANGED], 0, item->job, percentage);
 	pk_engine_reset_timer (engine);
 }
 
@@ -294,18 +214,18 @@ pk_engine_percentage_changed_cb (PkTask 
 static void
 pk_engine_sub_percentage_changed_cb (PkTask *task, guint percentage, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	pk_debug ("emitting sub-percentage-changed job:%i %i", map->job, percentage);
-	g_signal_emit (engine, signals [PK_ENGINE_SUB_PERCENTAGE_CHANGED], 0, map->job, percentage);
+	pk_debug ("emitting sub-percentage-changed job:%i %i", item->job, percentage);
+	g_signal_emit (engine, signals [PK_ENGINE_SUB_PERCENTAGE_CHANGED], 0, item->job, percentage);
 	pk_engine_reset_timer (engine);
 }
 
@@ -315,18 +235,18 @@ pk_engine_sub_percentage_changed_cb (PkT
 static void
 pk_engine_no_percentage_updates_cb (PkTask *task, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	pk_debug ("emitting no-percentage-updates job:%i", map->job);
-	g_signal_emit (engine, signals [PK_ENGINE_NO_PERCENTAGE_UPDATES], 0, map->job);
+	pk_debug ("emitting no-percentage-updates job:%i", item->job);
+	g_signal_emit (engine, signals [PK_ENGINE_NO_PERCENTAGE_UPDATES], 0, item->job);
 	pk_engine_reset_timer (engine);
 }
 
@@ -336,18 +256,18 @@ pk_engine_no_percentage_updates_cb (PkTa
 static void
 pk_engine_package_cb (PkTask *task, guint value, const gchar *package_id, const gchar *summary, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	pk_debug ("emitting package job:%i value=%i %s, %s", map->job, value, package_id, summary);
-	g_signal_emit (engine, signals [PK_ENGINE_PACKAGE], 0, map->job, value, package_id, summary);
+	pk_debug ("emitting package job:%i value=%i %s, %s", item->job, value, package_id, summary);
+	g_signal_emit (engine, signals [PK_ENGINE_PACKAGE], 0, item->job, value, package_id, summary);
 	pk_engine_reset_timer (engine);
 }
 
@@ -357,20 +277,20 @@ pk_engine_package_cb (PkTask *task, guin
 static void
 pk_engine_error_code_cb (PkTask *task, PkErrorCodeEnum code, const gchar *details, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	const gchar *code_text;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
 	code_text = pk_error_enum_to_text (code);
-	pk_debug ("emitting error-code job:%i %s, '%s'", map->job, code_text, details);
-	g_signal_emit (engine, signals [PK_ENGINE_ERROR_CODE], 0, map->job, code_text, details);
+	pk_debug ("emitting error-code job:%i %s, '%s'", item->job, code_text, details);
+	g_signal_emit (engine, signals [PK_ENGINE_ERROR_CODE], 0, item->job, code_text, details);
 	pk_engine_reset_timer (engine);
 }
 
@@ -380,20 +300,20 @@ pk_engine_error_code_cb (PkTask *task, P
 static void
 pk_engine_require_restart_cb (PkTask *task, PkRestartEnum restart, const gchar *details, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	const gchar *restart_text;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
 	restart_text = pk_restart_enum_to_text (restart);
-	pk_debug ("emitting error-code job:%i %s, '%s'", map->job, restart_text, details);
-	g_signal_emit (engine, signals [PK_ENGINE_REQUIRE_RESTART], 0, map->job, restart_text, details);
+	pk_debug ("emitting error-code job:%i %s, '%s'", item->job, restart_text, details);
+	g_signal_emit (engine, signals [PK_ENGINE_REQUIRE_RESTART], 0, item->job, restart_text, details);
 	pk_engine_reset_timer (engine);
 }
 
@@ -404,21 +324,21 @@ static void
 pk_engine_description_cb (PkTask *task, const gchar *package_id, PkGroupEnum group,
 			  const gchar *detail, const gchar *url, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	const gchar *group_text;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
 	group_text = pk_group_enum_to_text (group);
 
-	pk_debug ("emitting description job:%i, %s, %s, %s, %s", map->job, package_id, group_text, detail, url);
-	g_signal_emit (engine, signals [PK_ENGINE_DESCRIPTION], 0, map->job, package_id, group_text, detail, url);
+	pk_debug ("emitting description job:%i, %s, %s, %s, %s", item->job, package_id, group_text, detail, url);
+	g_signal_emit (engine, signals [PK_ENGINE_DESCRIPTION], 0, item->job, package_id, group_text, detail, url);
 }
 
 /**
@@ -427,15 +347,15 @@ pk_engine_description_cb (PkTask *task, 
 static void
 pk_engine_finished_cb (PkTask *task, PkExitEnum exit, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	const gchar *exit_text;
 	gdouble time;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
@@ -446,12 +366,11 @@ pk_engine_finished_cb (PkTask *task, PkE
 
 	pk_debug ("task was running for %f seconds", time);
 
-	pk_debug ("emitting finished job: %i, '%s', %i", map->job, exit_text, (guint) time);
-	g_signal_emit (engine, signals [PK_ENGINE_FINISHED], 0, map->job, exit_text, (guint) time);
+	pk_debug ("emitting finished job: %i, '%s', %i", item->job, exit_text, (guint) time);
+	g_signal_emit (engine, signals [PK_ENGINE_FINISHED], 0, item->job, exit_text, (guint) time);
 
 	/* remove from array and unref */
-	g_ptr_array_remove (engine->priv->array, map);
-	g_free (map);
+	pk_job_list_remove (engine->priv->job_list, task);
 
 	g_object_unref (task);
 	pk_debug ("removed task %p", task);
@@ -465,58 +384,19 @@ pk_engine_finished_cb (PkTask *task, PkE
 static void
 pk_engine_allow_interrupt_cb (PkTask *task, gboolean allow_kill, PkEngine *engine)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
 
-	pk_debug ("emitting allow-interrpt job:%i, %i", map->job, allow_kill);
-	g_signal_emit (engine, signals [PK_ENGINE_ALLOW_INTERRUPT], 0, map->job, allow_kill);
-}
-
-/**
- * pk_engine_load_job_count:
- **/
-static gboolean
-pk_engine_load_job_count (PkEngine *engine)
-{
-	gboolean ret;
-	gchar *contents;
-	ret = g_file_get_contents (PK_ENGINE_JOB_LAST_COUNT_FILE, &contents, NULL, NULL);
-	if (ret == FALSE) {
-		pk_warning ("failed to get last job");
-		return FALSE;
-	}
-	engine->priv->job_count = atoi (contents);
-	pk_debug ("job=%i", engine->priv->job_count);
-	g_free (contents);
-	return TRUE;
-}
-
-/**
- * pk_engine_save_job_count:
- **/
-static gboolean
-pk_engine_save_job_count (PkEngine *engine)
-{
-	gboolean ret;
-	gchar *contents;
-
-	pk_debug ("saving %i", engine->priv->job_count);
-	contents = g_strdup_printf ("%i", engine->priv->job_count);
-	ret = g_file_set_contents (PK_ENGINE_JOB_LAST_COUNT_FILE, contents, -1, NULL);
-	g_free (contents);
-	if (ret == FALSE) {
-		pk_warning ("failed to set last job");
-		return FALSE;
-	}
-	return TRUE;
+	pk_debug ("emitting allow-interrpt job:%i, %i", item->job, allow_kill);
+	g_signal_emit (engine, signals [PK_ENGINE_ALLOW_INTERRUPT], 0, item->job, allow_kill);
 }
 
 /**
@@ -528,9 +408,6 @@ pk_engine_new_task (PkEngine *engine)
 	PkTask *task;
 	gboolean ret;
 
-	/* increment the job number - we never repeat an id */
-	engine->priv->job_count++;
-
 	/* allocate a new task */
 	task = pk_backend_new ();
 	ret = pk_backend_load (task, engine->priv->backend);
@@ -564,6 +441,8 @@ pk_engine_new_task (PkEngine *engine)
 	/* initialise some stuff */
 	pk_engine_reset_timer (engine);
 
+	pk_job_list_add (engine->priv->job_list, task);
+
 	/* we don't add to the array or do the job-list-changed yet
 	 * as this job might fail */
 	return task;
@@ -575,20 +454,11 @@ pk_engine_new_task (PkEngine *engine)
 static gboolean
 pk_engine_add_task (PkEngine *engine, PkTask *task)
 {
-	PkEngineMap *map;
-
-	/* add to the array */
-	map = g_new0 (PkEngineMap, 1);
-	map->task = task;
-	map->job = engine->priv->job_count;
-	g_ptr_array_add (engine->priv->array, map);
-
-	/* in an ideal world we don't need this, but do it in case the daemon is ctrl-c;d */
-	pk_engine_save_job_count (engine);
+	/* commit, so it appears in the JobList */
+	pk_job_list_commit (engine->priv->job_list, task);
 
 	/* emit a signal */
 	pk_engine_job_list_changed (engine);
-
 	return TRUE;
 }
 
@@ -659,7 +529,7 @@ pk_engine_refresh_cache (PkEngine *engin
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -674,12 +544,12 @@ pk_engine_refresh_cache (PkEngine *engin
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -692,7 +562,7 @@ pk_engine_get_updates (PkEngine *engine,
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -707,12 +577,12 @@ pk_engine_get_updates (PkEngine *engine,
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -778,7 +648,7 @@ pk_engine_search_name (PkEngine *engine,
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -805,12 +675,12 @@ pk_engine_search_name (PkEngine *engine,
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -824,7 +694,7 @@ pk_engine_search_details (PkEngine *engi
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -851,12 +721,12 @@ pk_engine_search_details (PkEngine *engi
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -870,7 +740,7 @@ pk_engine_search_group (PkEngine *engine
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -897,12 +767,12 @@ pk_engine_search_group (PkEngine *engine
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -916,7 +786,7 @@ pk_engine_search_file (PkEngine *engine,
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -943,12 +813,12 @@ pk_engine_search_file (PkEngine *engine,
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -962,7 +832,7 @@ pk_engine_get_depends (PkEngine *engine,
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -985,12 +855,12 @@ pk_engine_get_depends (PkEngine *engine,
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -1004,7 +874,7 @@ pk_engine_get_requires (PkEngine *engine
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -1027,12 +897,12 @@ pk_engine_get_requires (PkEngine *engine
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -1046,7 +916,7 @@ pk_engine_get_description (PkEngine *eng
 {
 	gboolean ret;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -1061,12 +931,12 @@ pk_engine_get_description (PkEngine *eng
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return FALSE;
 	}
-	*job = map->job;
+	*job = item->job;
 
 	return TRUE;
 }
@@ -1078,13 +948,10 @@ void
 pk_engine_update_system (PkEngine *engine,
 			 DBusGMethodInvocation *context, GError **dead_error)
 {
-	guint i;
-	guint length;
-	PkRoleEnum role;
 	gboolean ret;
 	GError *error;
 	PkTask *task;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_if_fail (engine != NULL);
 	g_return_if_fail (PK_IS_ENGINE (engine));
@@ -1096,11 +963,15 @@ pk_engine_update_system (PkEngine *engin
 		return;
 	}
 
+#if 0
+	guint i;
+	guint length;
+	PkRoleEnum role;
 	/* check for existing job doing an update */
 	length = engine->priv->array->len;
 	for (i=0; i<length; i++) {
-		map = (PkEngineMap *) g_ptr_array_index (engine->priv->array, i);
-		ret = pk_backend_get_job_role (map->task, &role, NULL);
+		item = (PkJobListItem *) g_ptr_array_index (engine->priv->array, i);
+		ret = pk_backend_get_job_role (item->task, &role, NULL);
 		if (ret == TRUE && role == PK_ROLE_ENUM_SYSTEM_UPDATE) {
 			error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_DENIED,
 					     "operation not yet supported by backend");
@@ -1108,6 +979,7 @@ pk_engine_update_system (PkEngine *engin
 			return;
 		}
 	}
+#endif
 
 	/* create a new task and start it */
 	task = pk_engine_new_task (engine);
@@ -1121,12 +993,12 @@ pk_engine_update_system (PkEngine *engin
 	}
 	pk_engine_add_task (engine, task);
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	dbus_g_method_return (context, map->job);
+	dbus_g_method_return (context, item->job);
 }
 
 /**
@@ -1136,7 +1008,7 @@ void
 pk_engine_remove_package (PkEngine *engine, const gchar *package_id, gboolean allow_deps,
 			  DBusGMethodInvocation *context, GError **dead_error)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	gboolean ret;
 	PkTask *task;
 	GError *error;
@@ -1172,12 +1044,12 @@ pk_engine_remove_package (PkEngine *engi
 	}
 	pk_engine_add_task (engine, task);
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	dbus_g_method_return (context, map->job);
+	dbus_g_method_return (context, item->job);
 }
 
 /**
@@ -1190,7 +1062,7 @@ pk_engine_install_package (PkEngine *eng
 			   DBusGMethodInvocation *context, GError **dead_error)
 {
 	gboolean ret;
-	PkEngineMap *map;
+	PkJobListItem *item;
 	PkTask *task;
 	GError *error;
 
@@ -1225,12 +1097,12 @@ pk_engine_install_package (PkEngine *eng
 	}
 	pk_engine_add_task (engine, task);
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	dbus_g_method_return (context, map->job);
+	dbus_g_method_return (context, item->job);
 }
 
 /**
@@ -1243,7 +1115,7 @@ pk_engine_update_package (PkEngine *engi
 			   DBusGMethodInvocation *context, GError **dead_error)
 {
 	gboolean ret;
-	PkEngineMap *map;
+	PkJobListItem *item;
 	PkTask *task;
 	GError *error;
 
@@ -1278,12 +1150,12 @@ pk_engine_update_package (PkEngine *engi
 	}
 	pk_engine_add_task (engine, task);
 
-	map = pk_get_map_from_task (engine, task);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_task (engine->priv->job_list, task);
+	if (item == NULL) {
 		pk_warning ("could not find task");
 		return;
 	}
-	dbus_g_method_return (context, map->job);
+	dbus_g_method_return (context, item->job);
 }
 
 /**
@@ -1295,7 +1167,7 @@ pk_engine_get_job_list (PkEngine *engine
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	*job_list = pk_engine_create_job_list (engine);
+	*job_list = pk_job_list_get_array (engine->priv->job_list);
 
 	return TRUE;
 }
@@ -1308,18 +1180,18 @@ pk_engine_get_job_status (PkEngine *engi
 			  const gchar **status, GError **error)
 {
 	PkStatusEnum status_enum;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_job_status (map->task, &status_enum);
+	pk_backend_get_job_status (item->task, &status_enum);
 	*status = g_strdup (pk_status_enum_to_text (status_enum));
 
 	return TRUE;
@@ -1332,19 +1204,19 @@ gboolean
 pk_engine_get_job_role (PkEngine *engine, guint job,
 			const gchar **role, const gchar **package_id, GError **error)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 	PkRoleEnum role_enum;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_job_role (map->task, &role_enum, package_id);
+	pk_backend_get_job_role (item->task, &role_enum, package_id);
 	*role = g_strdup (pk_role_enum_to_text (role_enum));
 
 	return TRUE;
@@ -1356,18 +1228,18 @@ pk_engine_get_job_role (PkEngine *engine
 gboolean
 pk_engine_get_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_percentage (map->task, percentage);
+	pk_backend_get_percentage (item->task, percentage);
 	return TRUE;
 }
 
@@ -1377,18 +1249,18 @@ pk_engine_get_percentage (PkEngine *engi
 gboolean
 pk_engine_get_sub_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_sub_percentage (map->task, percentage);
+	pk_backend_get_sub_percentage (item->task, percentage);
 	return TRUE;
 }
 
@@ -1398,18 +1270,18 @@ pk_engine_get_sub_percentage (PkEngine *
 gboolean
 pk_engine_get_package (PkEngine *engine, guint job, gchar **package, GError **error)
 {
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_package (map->task, package);
+	pk_backend_get_package (item->task, package);
 	return TRUE;
 }
 
@@ -1420,19 +1292,19 @@ gboolean
 pk_engine_cancel_job_try (PkEngine *engine, guint job, GError **error)
 {
 	gboolean ret;
-	PkEngineMap *map;
+	PkJobListItem *item;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
-	map = pk_get_map_from_job (engine, job);
-	if (map == NULL) {
+	item = pk_job_list_get_item_from_job (engine->priv->job_list, job);
+	if (item == NULL) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
 			     "No job:%i", job);
 		return FALSE;
 	}
 
-	ret = pk_backend_cancel_job_try (map->task);
+	ret = pk_backend_cancel_job_try (item->task);
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "operation not yet supported by backend");
@@ -1528,7 +1400,7 @@ pk_engine_get_seconds_idle (PkEngine *en
 
 	/* check for jobs running - a job that takes a *long* time might not
 	 * give sufficient percentage updates to not be marked as idle */
-	if (engine->priv->array->len != 0) {
+	if (pk_job_list_get_size (engine->priv->job_list) != 0) {
 		pk_debug ("engine idle zero as jobs in progress");
 		return 0;
 	}
@@ -1621,12 +1493,10 @@ pk_engine_init (PkEngine *engine)
 	PolKitError *pk_error;
 
 	engine->priv = PK_ENGINE_GET_PRIVATE (engine);
-	engine->priv->array = g_ptr_array_new ();
+	engine->priv->job_list = pk_job_list_new ();
 	engine->priv->timer = g_timer_new ();
 	engine->priv->backend = NULL;
 
-	engine->priv->job_count = pk_engine_load_job_count (engine);
-
 	/* get a connection to the bus */
 	dbus_error_init (&dbus_error);
 	engine->priv->connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
@@ -1660,14 +1530,11 @@ pk_engine_finalize (GObject *object)
 
 	g_return_if_fail (engine->priv != NULL);
 
-	/* save last job id so we don't ever repeat */
-	pk_engine_save_job_count (engine);
-
 	/* compulsory gobjects */
-	g_ptr_array_free (engine->priv->array, TRUE);
 	g_timer_destroy (engine->priv->timer);
 	g_free (engine->priv->backend);
 	polkit_context_unref (engine->priv->pk_context);
+	g_object_unref (engine->priv->job_list);
 
 	G_OBJECT_CLASS (pk_engine_parent_class)->finalize (object);
 }
diff --git a/src/pk-job-list.c b/src/pk-job-list.c
new file mode 100644
index 0000000..e790669
--- /dev/null
+++ b/src/pk-job-list.c
@@ -0,0 +1,357 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <glib/gi18n.h>
+#include "pk-debug.h"
+#include "pk-job-list.h"
+
+static void     pk_job_list_class_init	(PkJobListClass *klass);
+static void     pk_job_list_init	(PkJobList      *job_list);
+static void     pk_job_list_finalize	(GObject        *object);
+
+#define PK_JOB_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_JOB_LIST, PkJobListPrivate))
+#define PK_JOB_LIST_COUNT_FILE		LOCALSTATEDIR "/run/PackageKit/job_count.dat"
+
+struct PkJobListPrivate
+{
+	GPtrArray		*array;
+	guint			 job_count;
+};
+
+enum {
+	PK_JOB_LIST_CHANGED,
+	PK_JOB_LIST_LAST_SIGNAL
+};
+
+static guint signals [PK_JOB_LIST_LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (PkJobList, pk_job_list, G_TYPE_OBJECT)
+
+/**
+ * pk_job_list_load_job_count:
+ **/
+static gboolean
+pk_job_list_load_job_count (PkJobList *job_list)
+{
+	gboolean ret;
+	gchar *contents;
+	ret = g_file_get_contents (PK_JOB_LIST_COUNT_FILE, &contents, NULL, NULL);
+	if (ret == FALSE) {
+		pk_warning ("failed to get last job");
+		return FALSE;
+	}
+	job_list->priv->job_count = atoi (contents);
+	pk_debug ("job=%i", job_list->priv->job_count);
+	g_free (contents);
+	return TRUE;
+}
+
+/**
+ * pk_job_list_save_job_count:
+ **/
+static gboolean
+pk_job_list_save_job_count (PkJobList *job_list)
+{
+	gboolean ret;
+	gchar *contents;
+
+	pk_debug ("saving %i", job_list->priv->job_count);
+	contents = g_strdup_printf ("%i", job_list->priv->job_count);
+	ret = g_file_set_contents (PK_JOB_LIST_COUNT_FILE, contents, -1, NULL);
+	g_free (contents);
+	if (ret == FALSE) {
+		pk_warning ("failed to set last job");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * pk_job_list_add:
+ **/
+ /* create transaction_id, add to array, mark changed */
+PkJobListItem *
+pk_job_list_add (PkJobList *job_list, PkTask *task)
+{
+	PkJobListItem *item;
+
+	g_return_val_if_fail (job_list != NULL, NULL);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), NULL);
+
+	/* increment the job number - we never repeat an id */
+	job_list->priv->job_count++;
+
+	/* add to the array */
+	item = g_new0 (PkJobListItem, 1);
+	item->valid = FALSE;
+	item->task = task;
+	item->job = job_list->priv->job_count;
+	g_ptr_array_add (job_list->priv->array, item);
+
+	/* in an ideal world we don't need this, but do it in case the daemon is ctrl-c;d */
+	pk_job_list_save_job_count (job_list);
+	return item;
+}
+
+/**
+ * pk_job_list_remove:
+ **/
+gboolean
+pk_job_list_remove (PkJobList *job_list, PkTask *task)
+{
+	PkJobListItem *item;
+	g_return_val_if_fail (job_list != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), FALSE);
+
+	item = pk_job_list_get_item_from_task (job_list, task);
+	if (item == NULL) {
+		return FALSE;
+	}
+	g_ptr_array_remove (job_list->priv->array, item);
+	g_free (item);
+	return TRUE;
+}
+
+/**
+ * pk_job_list_commit:
+ **/
+gboolean
+pk_job_list_commit (PkJobList *job_list, PkTask *task)
+{
+	PkJobListItem *item;
+	g_return_val_if_fail (job_list != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), FALSE);
+
+	item = pk_job_list_get_item_from_task (job_list, task);
+	if (item == NULL) {
+		return FALSE;
+	}
+	pk_debug ("marking job %i as valid", item->job);
+	item->valid = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_job_list_get_array:
+ **/
+GArray *
+pk_job_list_get_array (PkJobList *job_list)
+{
+	guint i;
+	guint length;
+	GArray *array;
+	PkJobListItem *item;
+
+	g_return_val_if_fail (job_list != NULL, NULL);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), NULL);
+
+	/* create new list */
+	array = g_array_new (FALSE, FALSE, sizeof (guint));
+
+	/* find all the jobs in progress */
+	length = job_list->priv->array->len;
+	for (i=0; i<length; i++) {
+		item = (PkJobListItem *) g_ptr_array_index (job_list->priv->array, i);
+		/* only return in the list if it worked */
+		if (item->valid == TRUE) {
+			array = g_array_append_val (array, item->job);
+		}
+	}
+	return array;
+}
+
+/**
+ * pk_job_list_get_size:
+ **/
+guint
+pk_job_list_get_size (PkJobList *job_list)
+{
+	g_return_val_if_fail (job_list != NULL, 0);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), 0);
+	return job_list->priv->array->len;
+}
+
+/**
+ * pk_job_list_get_item_from_job:
+ **/
+PkJobListItem *
+pk_job_list_get_item_from_job (PkJobList *job_list, guint job)
+{
+	guint i;
+	guint length;
+	PkJobListItem *item;
+
+	g_return_val_if_fail (job_list != NULL, NULL);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), NULL);
+
+	/* find the task with the job ID */
+	length = job_list->priv->array->len;
+	for (i=0; i<length; i++) {
+		item = (PkJobListItem *) g_ptr_array_index (job_list->priv->array, i);
+		if (item->job == job) {
+			return item;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * pk_job_list_get_item_from_task:
+ **/
+PkJobListItem *
+pk_job_list_get_item_from_task (PkJobList *job_list, PkTask *task)
+{
+	guint i;
+	guint length;
+	PkJobListItem *item;
+
+	g_return_val_if_fail (job_list != NULL, NULL);
+	g_return_val_if_fail (PK_IS_JOB_LIST (job_list), NULL);
+
+	/* find the task with the job ID */
+	length = job_list->priv->array->len;
+	for (i=0; i<length; i++) {
+		item = (PkJobListItem *) g_ptr_array_index (job_list->priv->array, i);
+		if (item->task == task) {
+			return item;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * pk_job_list_class_init:
+ * @klass: The PkJobListClass
+ **/
+static void
+pk_job_list_class_init (PkJobListClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = pk_job_list_finalize;
+
+	signals [PK_JOB_LIST_CHANGED] =
+		g_signal_new ("changed",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+	g_type_class_add_private (klass, sizeof (PkJobListPrivate));
+}
+
+/**
+ * pk_job_list_init:
+ * @job_list: This class instance
+ **/
+static void
+pk_job_list_init (PkJobList *job_list)
+{
+	job_list->priv = PK_JOB_LIST_GET_PRIVATE (job_list);
+	job_list->priv->array = g_ptr_array_new ();
+	job_list->priv->job_count = pk_job_list_load_job_count (job_list);
+}
+
+/**
+ * pk_job_list_finalize:
+ * @object: The object to finalize
+ **/
+static void
+pk_job_list_finalize (GObject *object)
+{
+	PkJobList *job_list;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (PK_IS_JOB_LIST (object));
+
+	job_list = PK_JOB_LIST (object);
+
+	g_return_if_fail (job_list->priv != NULL);
+
+	g_ptr_array_free (job_list->priv->array, TRUE);
+	/* save last job id so we don't ever repeat */
+	pk_job_list_save_job_count (job_list);
+
+	G_OBJECT_CLASS (pk_job_list_parent_class)->finalize (object);
+}
+
+/**
+ * pk_job_list_new:
+ *
+ * Return value: a new PkJobList object.
+ **/
+PkJobList *
+pk_job_list_new (void)
+{
+	PkJobList *job_list;
+	job_list = g_object_new (PK_TYPE_JOB_LIST, NULL);
+	return PK_JOB_LIST (job_list);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef PK_BUILD_TESTS
+#include <libselftest.h>
+
+static GMainLoop *loop;
+
+void
+libst_job_list (LibSelfTest *test)
+{
+	PkJobList *job_list;
+	gboolean ret;
+
+	if (libst_start (test, "PkJobList", CLASS_AUTO) == FALSE) {
+		return;
+	}
+
+	job_list = pk_job_list_new ();
+
+	/************************************************************/
+	libst_title (test, "make sure return error for missing file");
+	ret = pk_job_list_foo (job_list, " ");
+	if (ret == FALSE) {
+		libst_success (test, "failed to run invalid file");
+	} else {
+		libst_failed (test, "ran incorrect file");
+	}
+
+	g_object_unref (job_list);
+
+	libst_end (test);
+}
+#endif
+
diff --git a/src/pk-job-list.h b/src/pk-job-list.h
new file mode 100644
index 0000000..d930fed
--- /dev/null
+++ b/src/pk-job-list.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_JOB_LIST_H
+#define __PK_JOB_LIST_H
+
+#include <glib-object.h>
+#include "pk-backend-internal.h"
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_JOB_LIST		(pk_job_list_get_type ())
+#define PK_JOB_LIST(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_JOB_LIST, PkJobList))
+#define PK_JOB_LIST_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_JOB_LIST, PkJobListClass))
+#define PK_IS_JOB_LIST(o)	 	(G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_JOB_LIST))
+#define PK_IS_JOB_LIST_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_JOB_LIST))
+#define PK_JOB_LIST_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_JOB_LIST, PkJobListClass))
+#define PK_JOB_LIST_ERROR		(pk_job_list_error_quark ())
+#define PK_JOB_LIST_TYPE_ERROR		(pk_job_list_error_get_type ()) 
+
+typedef struct PkJobListPrivate PkJobListPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 PkJobListPrivate	*priv;
+} PkJobList;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} PkJobListClass;
+
+typedef struct {
+	guint		 job;
+	gboolean	 valid;
+	PkTask		*task;
+} PkJobListItem;
+
+GType		 pk_job_list_get_type		  	(void);
+PkJobList	*pk_job_list_new			(void);
+
+PkJobListItem	*pk_job_list_add			(PkJobList	*job_list,
+							 PkTask		*task);
+gboolean	 pk_job_list_remove			(PkJobList	*job_list,
+							 PkTask		*task);
+gboolean	 pk_job_list_commit			(PkJobList	*job_list,
+							 PkTask		*task);
+GArray		*pk_job_list_get_array			(PkJobList	*job_list);
+guint		 pk_job_list_get_size			(PkJobList	*job_list);
+PkJobListItem	*pk_job_list_get_item_from_job		(PkJobList	*job_list,
+							 guint		 job);
+PkJobListItem	*pk_job_list_get_item_from_task		(PkJobList	*job_list,
+							 PkTask		*task);
+
+G_END_DECLS
+
+#endif /* __PK_JOB_LIST_H */
diff-tree 168dccfeb1bb6fd5748c72b3e524ab7e4f0bf6c1 (from ff19a54e01d74e7999ccc81f26d238764246bfe5)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 9 21:11:26 2007 +0100

    Add GetPackage, GetPercentage and GetSubPercentage so we can coldplug in the monitoring code

diff --git a/TODO b/TODO
index 182df55..65e8470 100644
--- a/TODO
+++ b/TODO
@@ -22,10 +22,6 @@ to expose in the UI.
 *** Valgrind everything ***
 We leak memory like there is no tommorrow.
 
-*** Add methods for coldplugging ***
-We need GetLastPackage, GetLastPercentage and GetLastSubPercentage for the PkWatch code.
-NOTE: RELEASE BLOCKER
-
 *** task_client has to return GError ***
 Client programs using libpackagekit should know the error, rather than just
 "it failed"
diff --git a/libpackagekit/pk-task-monitor.c b/libpackagekit/pk-task-monitor.c
index 322c043..bdf99a0 100644
--- a/libpackagekit/pk-task-monitor.c
+++ b/libpackagekit/pk-task-monitor.c
@@ -124,6 +124,102 @@ pk_task_monitor_get_status (PkTaskMonito
 }
 
 /**
+ * pk_task_monitor_get_package:
+ **/
+gboolean
+pk_task_monitor_get_package (PkTaskMonitor *tmonitor, gchar **package)
+{
+	gboolean ret;
+	GError *error;
+
+	g_return_val_if_fail (tmonitor != NULL, FALSE);
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TASK_MONITOR (tmonitor), FALSE);
+	g_return_val_if_fail (tmonitor->priv->job != 0, FALSE);
+
+	error = NULL;
+	ret = dbus_g_proxy_call (tmonitor->priv->proxy, "GetPackage", &error,
+				 G_TYPE_UINT, tmonitor->priv->job,
+				 G_TYPE_INVALID,
+				 G_TYPE_STRING, package,
+				 G_TYPE_INVALID);
+	if (error) {
+		pk_debug ("ERROR: %s", error->message);
+		g_error_free (error);
+	}
+	if (ret == FALSE) {
+		/* abort as the DBUS method failed */
+		pk_warning ("GetPackage failed!");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * pk_task_monitor_get_percentage:
+ **/
+gboolean
+pk_task_monitor_get_percentage (PkTaskMonitor *tmonitor, guint *percentage)
+{
+	gboolean ret;
+	GError *error;
+
+	g_return_val_if_fail (tmonitor != NULL, FALSE);
+	g_return_val_if_fail (percentage != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TASK_MONITOR (tmonitor), FALSE);
+	g_return_val_if_fail (tmonitor->priv->job != 0, FALSE);
+
+	error = NULL;
+	ret = dbus_g_proxy_call (tmonitor->priv->proxy, "GetPercentage", &error,
+				 G_TYPE_UINT, tmonitor->priv->job,
+				 G_TYPE_INVALID,
+				 G_TYPE_UINT, percentage,
+				 G_TYPE_INVALID);
+	if (error) {
+		pk_debug ("ERROR: %s", error->message);
+		g_error_free (error);
+	}
+	if (ret == FALSE) {
+		/* abort as the DBUS method failed */
+		pk_warning ("GetPercentage failed!");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * pk_task_monitor_get_sub_percentage:
+ **/
+gboolean
+pk_task_monitor_get_sub_percentage (PkTaskMonitor *tmonitor, guint *percentage)
+{
+	gboolean ret;
+	GError *error;
+
+	g_return_val_if_fail (tmonitor != NULL, FALSE);
+	g_return_val_if_fail (percentage != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TASK_MONITOR (tmonitor), FALSE);
+	g_return_val_if_fail (tmonitor->priv->job != 0, FALSE);
+
+	error = NULL;
+	ret = dbus_g_proxy_call (tmonitor->priv->proxy, "GetSubPercentage", &error,
+				 G_TYPE_UINT, tmonitor->priv->job,
+				 G_TYPE_INVALID,
+				 G_TYPE_UINT, percentage,
+				 G_TYPE_INVALID);
+	if (error) {
+		pk_debug ("ERROR: %s", error->message);
+		g_error_free (error);
+	}
+	if (ret == FALSE) {
+		/* abort as the DBUS method failed */
+		pk_warning ("GetSubPercentage failed!");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
  * pk_task_monitor_get_role:
  **/
 gboolean
diff --git a/libpackagekit/pk-task-monitor.h b/libpackagekit/pk-task-monitor.h
index 3141839..2a63915 100644
--- a/libpackagekit/pk-task-monitor.h
+++ b/libpackagekit/pk-task-monitor.h
@@ -58,6 +58,12 @@ gboolean	 pk_task_monitor_get_status		(P
 gboolean	 pk_task_monitor_get_role		(PkTaskMonitor	*tmonitor,
 							 PkRoleEnum	*role,
 							 gchar		**package_id);
+gboolean	 pk_task_monitor_get_percentage		(PkTaskMonitor	*tmonitor,
+							 guint		*percentage);
+gboolean	 pk_task_monitor_get_sub_percentage	(PkTaskMonitor	*tmonitor,
+							 guint		*percentage);
+gboolean	 pk_task_monitor_get_package		(PkTaskMonitor	*tmonitor,
+							 gchar		**package_id);
 
 G_END_DECLS
 
diff --git a/src/pk-backend-internal.h b/src/pk-backend-internal.h
index 7e0129f..ad6aaee 100644
--- a/src/pk-backend-internal.h
+++ b/src/pk-backend-internal.h
@@ -98,6 +98,12 @@ gboolean	 pk_backend_get_job_status		(Pk
 gboolean	 pk_backend_get_job_role		(PkBackend	*backend,
 							 PkRoleEnum	*role,
 							 const gchar	**package_id);
+gboolean	 pk_backend_get_percentage		(PkBackend	*backend,
+							 guint		*percentage);
+gboolean	 pk_backend_get_sub_percentage		(PkBackend	*backend,
+							 guint		*percentage);
+gboolean	 pk_backend_get_package			(PkBackend	*backend,
+							 gchar		**package_id);
 
 /* these are external in nature, but we shouldn't be using them in helpers */
 gboolean	 pk_backend_set_job_role		(PkBackend	*backend,
diff --git a/src/pk-backend.c b/src/pk-backend.c
index d591b84..625fb87 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -62,6 +62,10 @@ struct _PkBackendPrivate
 	gboolean		 is_killable;
 	gboolean		 assigned;
 	PkNetwork		*network;
+	/* needed for gui coldplugging */
+	guint			 last_percentage;
+	guint			 last_subpercentage;
+	gchar			*last_package;
 };
 
 enum {
@@ -445,6 +449,10 @@ pk_backend_change_percentage (PkBackend 
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* save in case we need this from coldplug */
+	backend->priv->last_subpercentage = percentage;
+
 	pk_debug ("emit percentage-changed %i", percentage);
 	g_signal_emit (backend, signals [PK_TASK_PERCENTAGE_CHANGED], 0, percentage);
 	return TRUE;
@@ -458,6 +466,10 @@ pk_backend_change_sub_percentage (PkBack
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* save in case we need this from coldplug */
+	backend->priv->last_subpercentage = percentage;
+
 	pk_debug ("emit sub-percentage-changed %i", percentage);
 	g_signal_emit (backend, signals [PK_TASK_SUB_PERCENTAGE_CHANGED], 0, percentage);
 	return TRUE;
@@ -507,6 +519,10 @@ pk_backend_package (PkBackend *backend, 
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
+	/* save in case we need this from coldplug */
+	g_free (backend->priv->last_package);
+	backend->priv->last_package = g_strdup (package);
+
 	pk_debug ("emit package %i, %s, %s", value, package, summary);
 	g_signal_emit (backend, signals [PK_TASK_PACKAGE], 0, value, package, summary);
 
@@ -514,6 +530,42 @@ pk_backend_package (PkBackend *backend, 
 }
 
 /**
+ * pk_backend_get_percentage:
+ **/
+gboolean
+pk_backend_get_percentage (PkBackend	*backend, guint *percentage)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	*percentage = backend->priv->last_percentage;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_sub_percentage:
+ **/
+gboolean
+pk_backend_get_sub_percentage (PkBackend *backend, guint *percentage)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	*percentage = backend->priv->last_subpercentage;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_package:
+ **/
+gboolean
+pk_backend_get_package (PkBackend *backend, gchar **package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	*package_id = g_strdup (backend->priv->last_package);
+	return TRUE;
+}
+
+/**
  * pk_backend_require_restart:
  **/
 gboolean
@@ -1042,6 +1094,7 @@ pk_backend_finalize (GObject *object)
 	g_free (backend->priv->name);
 	pk_backend_unload (backend);
 	g_timer_destroy (backend->priv->timer);
+	g_free (backend->priv->last_package);
 	g_object_unref (backend->priv->network);
 
 	G_OBJECT_CLASS (pk_backend_parent_class)->finalize (object);
@@ -1123,6 +1176,9 @@ pk_backend_init (PkBackend *backend)
 	backend->priv->is_killable = FALSE;
 	backend->priv->spawn = NULL;
 	backend->priv->package_id = NULL;
+	backend->priv->last_percentage = 0;
+	backend->priv->last_subpercentage = 0;
+	backend->priv->last_package = NULL;
 	backend->priv->role = PK_ROLE_ENUM_UNKNOWN;
 	backend->priv->status = PK_STATUS_ENUM_UNKNOWN;
 	backend->priv->exit = PK_EXIT_ENUM_UNKNOWN;
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 4a0a04e..8c4dd8c 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -1351,6 +1351,69 @@ pk_engine_get_job_role (PkEngine *engine
 }
 
 /**
+ * pk_engine_get_percentage:
+ **/
+gboolean
+pk_engine_get_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
+{
+	PkEngineMap *map;
+
+	g_return_val_if_fail (engine != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
+
+	map = pk_get_map_from_job (engine, job);
+	if (map == NULL) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
+			     "No job:%i", job);
+		return FALSE;
+	}
+	pk_backend_get_percentage (map->task, percentage);
+	return TRUE;
+}
+
+/**
+ * pk_engine_get_sub_percentage:
+ **/
+gboolean
+pk_engine_get_sub_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
+{
+	PkEngineMap *map;
+
+	g_return_val_if_fail (engine != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
+
+	map = pk_get_map_from_job (engine, job);
+	if (map == NULL) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
+			     "No job:%i", job);
+		return FALSE;
+	}
+	pk_backend_get_sub_percentage (map->task, percentage);
+	return TRUE;
+}
+
+/**
+ * pk_engine_get_package:
+ **/
+gboolean
+pk_engine_get_package (PkEngine *engine, guint job, gchar **package, GError **error)
+{
+	PkEngineMap *map;
+
+	g_return_val_if_fail (engine != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
+
+	map = pk_get_map_from_job (engine, job);
+	if (map == NULL) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NO_SUCH_JOB,
+			     "No job:%i", job);
+		return FALSE;
+	}
+	pk_backend_get_package (map->task, package);
+	return TRUE;
+}
+
+/**
  * pk_engine_cancel_job_try:
  **/
 gboolean
diff --git a/src/pk-engine.h b/src/pk-engine.h
index b954a86..3906db8 100644
--- a/src/pk-engine.h
+++ b/src/pk-engine.h
@@ -153,6 +153,19 @@ gboolean	 pk_engine_get_filters			(PkEng
 							 GError		**error);
 guint		 pk_engine_get_seconds_idle		(PkEngine	*engine);
 
+gboolean	 pk_engine_get_percentage		(PkEngine	*engine,
+							 guint		 job,
+							 guint		*percentage,
+							 GError		**error);
+gboolean	 pk_engine_get_sub_percentage		(PkEngine	*engine,
+							 guint		 job,
+							 guint		*percentage,
+							 GError		**error);
+gboolean	 pk_engine_get_package			(PkEngine	*engine,
+							 guint		 job,
+							 gchar		**package,
+							 GError		**error);
+
 G_END_DECLS
 
 #endif /* __PK_ENGINE_H */
diff --git a/src/pk-interface.xml b/src/pk-interface.xml
index 1a5901b..d025277 100644
--- a/src/pk-interface.xml
+++ b/src/pk-interface.xml
@@ -124,10 +124,25 @@
     </method>
     <method name="GetJobRole"> <!-- this is the master role, i.e. won't change for the lifetime of the job -->
       <!-- throws NoSuchJob -->
-      <arg type="u" name="job" direction="in"/> 
+      <arg type="u" name="job" direction="in"/>
       <arg type="s" name="status" direction="out"/> <!-- query,download,install,exit -->
       <arg type="s" name="package_id" direction="out"/> <!-- what we are doing the action to, or NULL -->
     </method>
+    <method name="GetPercentage">
+      <!-- throws NoSuchJob -->
+      <arg type="u" name="job" direction="in"/>
+      <arg type="u" name="percentage" direction="out"/>
+    </method>
+    <method name="GetSubPercentage">
+      <!-- throws NoSuchJob -->
+      <arg type="u" name="job" direction="in"/>
+      <arg type="u" name="percentage" direction="out"/>
+    </method>
+    <method name="GetPackage">
+      <!-- throws NoSuchJob -->
+      <arg type="u" name="job" direction="in"/>
+      <arg type="s" name="package" direction="out"/>
+    </method>
 
     <!-- Job list -->
     <method name="GetJobList">
diff --git a/tools/add-error-enum.sh b/tools/add-error-enum.sh
index fe7c0cd..f6efe85 100755
--- a/tools/add-error-enum.sh
+++ b/tools/add-error-enum.sh
@@ -1,4 +1,4 @@
 #!/bin/sh
 
-$EDITOR backends/README libpackagekit/pk-enum.h libpackagekit/pk-task-utils.c ../gnome-packagekit/src/pk-common.c backends/yum/helpers/packagekit.py
+$EDITOR docs/introduction.xml libpackagekit/pk-enum.h libpackagekit/pk-enum.c ../gnome-packagekit/src/pk-common.c backends/yum/helpers/packagekit.py
 
diff --git a/tools/add-method.sh b/tools/add-method.sh
new file mode 100755
index 0000000..147b0ca
--- /dev/null
+++ b/tools/add-method.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+$EDITOR docs/introduction.xml src/pk-interface.xml src/pk-engine.h src/pk-engine.c backends/yum/helpers/packagekit.py libpackagekit/pk-task-client.h libpackagekit/pk-task-client.c
+



More information about the PackageKit mailing list