gnome-packagekit r545 - in trunk: data po src



Author: rhughes
Date: Tue Apr 14 16:28:59 2009
New Revision: 545
URL: http://svn.gnome.org/viewvc/gnome-packagekit?rev=545&view=rev

Log:
from git

Added:
   trunk/src/egg-markdown.c
   trunk/src/egg-markdown.h
   trunk/src/gpk-dbus-task.c
   trunk/src/gpk-dbus-task.h
   trunk/src/gpk-helper-chooser.c
   trunk/src/gpk-helper-chooser.h
   trunk/src/gpk-helper-deps-install.c
   trunk/src/gpk-helper-deps-install.h
   trunk/src/gpk-helper-deps-remove.c
   trunk/src/gpk-helper-deps-remove.h
   trunk/src/gpk-helper-media-change.c
   trunk/src/gpk-helper-media-change.h
   trunk/src/gpk-helper-run.c
   trunk/src/gpk-helper-run.h
   trunk/src/gpk-helper-untrusted.c
   trunk/src/gpk-helper-untrusted.h
   trunk/src/gpk-modal-dialog.c
   trunk/src/gpk-modal-dialog.h
Removed:
   trunk/src/gpk-client-chooser.c
   trunk/src/gpk-client-chooser.h
   trunk/src/gpk-client-dialog.c
   trunk/src/gpk-client-dialog.h
   trunk/src/gpk-client-eula.c
   trunk/src/gpk-client-eula.h
   trunk/src/gpk-client-run.c
   trunk/src/gpk-client-run.h
   trunk/src/gpk-client-signature.c
   trunk/src/gpk-client-signature.h
   trunk/src/gpk-client-untrusted.c
   trunk/src/gpk-client-untrusted.h
   trunk/src/gpk-client.c
   trunk/src/gpk-client.h
Modified:
   trunk/data/gnome-packagekit.schemas.in
   trunk/data/gpk-application.ui
   trunk/data/gpk-log.ui
   trunk/data/gpk-update-viewer.desktop.in
   trunk/data/gpk-update-viewer.ui
   trunk/po/POTFILES.in
   trunk/src/Makefile.am
   trunk/src/gpk-application.c
   trunk/src/gpk-auto-refresh.c
   trunk/src/gpk-cell-renderer-info.c
   trunk/src/gpk-check-update.c
   trunk/src/gpk-common.h
   trunk/src/gpk-dbus.c
   trunk/src/gpk-dbus.h
   trunk/src/gpk-dialog.c
   trunk/src/gpk-enum.c
   trunk/src/gpk-enum.h
   trunk/src/gpk-error.c
   trunk/src/gpk-firmware.c
   trunk/src/gpk-hardware.c
   trunk/src/gpk-helper-eula.c
   trunk/src/gpk-helper-repo-signature.c
   trunk/src/gpk-install-catalog.c
   trunk/src/gpk-install-local-file.c
   trunk/src/gpk-install-mime-type.c
   trunk/src/gpk-install-package-name.c
   trunk/src/gpk-install-provide-file.c
   trunk/src/gpk-self-test.c
   trunk/src/gpk-update-viewer.c
   trunk/src/gpk-vendor.h
   trunk/src/gpk-watch.c
   trunk/src/org.freedesktop.PackageKit.xml

Modified: trunk/data/gnome-packagekit.schemas.in
==============================================================================
--- trunk/data/gnome-packagekit.schemas.in	(original)
+++ trunk/data/gnome-packagekit.schemas.in	Tue Apr 14 16:28:59 2009
@@ -389,8 +389,8 @@
     </schema>
 
     <schema>
-      <key>/schemas/apps/gnome-packagekit/update_viewer/precache_details</key>
-      <applyto>/apps/gnome-packagekit/update_viewer/precache_details</applyto>
+      <key>/schemas/apps/gnome-packagekit/update-viewer/precache_details</key>
+      <applyto>/apps/gnome-packagekit/update-viewer/precache_details</applyto>
       <owner>gnome-packagekit</owner>
       <type>bool</type>
       <default>true</default>
@@ -401,6 +401,18 @@
     </schema>
 
     <schema>
+      <key>/schemas/apps/gnome-packagekit/update-viewer/notify_mobile_connection</key>
+      <applyto>/apps/gnome-packagekit/update-viewer/notify_mobile_connection</applyto>
+      <owner>gnome-packagekit</owner>
+      <type>bool</type>
+      <default>true</default>
+      <locale name="C">
+        <short>Notify the user before a large update is done on a mobile broadband connection</short>
+        <long>Notify the user before a large update is done on a mobile broadband connection</long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/gnome-packagekit/enable_font_helper</key>
       <applyto>/apps/gnome-packagekit/enable_font_helper</applyto>
       <owner>gnome-packagekit</owner>

Modified: trunk/data/gpk-application.ui
==============================================================================
--- trunk/data/gpk-application.ui	(original)
+++ trunk/data/gpk-application.ui	Tue Apr 14 16:28:59 2009
@@ -478,64 +478,12 @@
                                   </packing>
                                 </child>
                                 <child>
-                                  <object class="GtkNotebook" id="notebook_search_cancel">
+                                  <object class="GtkButton" id="button_find">
+                                    <property name="label" translatable="yes">Fi_nd</property>
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
-                                    <property name="show_tabs">False</property>
-                                    <property name="show_border">False</property>
-                                    <property name="tab_border">0</property>
-                                    <property name="tab_hborder">0</property>
-                                    <property name="tab_vborder">0</property>
-                                    <child>
-                                      <object class="GtkButton" id="button_find">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <child>
-                                          <object class="GtkLabel" id="label_button_find">
-                                            <property name="visible">True</property>
-                                            <property name="label" translatable="yes">Fi_nd</property>
-                                            <property name="use_underline">True</property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                    </child>
-                                    <child type="tab">
-                                      <object class="GtkLabel" id="label_find">
-                                        <property name="visible">True</property>
-                                        <property name="label">find</property>
-                                      </object>
-                                      <packing>
-                                        <property name="tab_fill">False</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkButton" id="button_cancel">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <child>
-                                          <object class="GtkLabel" id="label_button_cancel">
-                                            <property name="visible">True</property>
-                                            <property name="label" translatable="yes">_Cancel</property>
-                                            <property name="use_underline">True</property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                    <child type="tab">
-                                      <object class="GtkLabel" id="label_cancel">
-                                        <property name="visible">True</property>
-                                        <property name="label">cancel</property>
-                                      </object>
-                                      <packing>
-                                        <property name="position">1</property>
-                                        <property name="tab_fill">False</property>
-                                      </packing>
-                                    </child>
+                                    <property name="receives_default">True</property>
+                                    <property name="use_underline">True</property>
                                   </object>
                                   <packing>
                                     <property name="position">1</property>
@@ -570,6 +518,15 @@
                               </packing>
                             </child>
                             <child>
+                              <object class="GtkProgressBar" id="progressbar_progress">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
                               <object class="GtkHBox" id="hbox_status">
                                 <property name="spacing">6</property>
                                 <child>
@@ -587,7 +544,7 @@
                               </object>
                               <packing>
                                 <property name="expand">False</property>
-                                <property name="position">2</property>
+                                <property name="position">3</property>
                               </packing>
                             </child>
                           </object>
@@ -709,6 +666,20 @@
                       </packing>
                     </child>
                     <child>
+                      <object class="GtkButton" id="button_cancel">
+                        <property name="label" translatable="yes">gtk-cancel</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
                       <object class="GtkButton" id="button_clear">
                         <property name="label">gtk-clear</property>
                         <property name="visible">True</property>
@@ -719,7 +690,7 @@
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="position">1</property>
+                        <property name="position">2</property>
                       </packing>
                     </child>
                     <child>
@@ -733,7 +704,7 @@
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="position">2</property>
+                        <property name="position">3</property>
                       </packing>
                     </child>
                   </object>

Modified: trunk/data/gpk-log.ui
==============================================================================
--- trunk/data/gpk-log.ui	(original)
+++ trunk/data/gpk-log.ui	Tue Apr 14 16:28:59 2009
@@ -6,7 +6,7 @@
     <property name="border_width">6</property>
     <property name="title" translatable="yes">Software Log Viewer</property>
     <property name="window_position">center-on-parent</property>
-    <property name="type_hint">dialog</property>
+    <property name="type_hint">normal</property>
     <property name="has_separator">False</property>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">

Modified: trunk/data/gpk-update-viewer.desktop.in
==============================================================================
--- trunk/data/gpk-update-viewer.desktop.in	(original)
+++ trunk/data/gpk-update-viewer.desktop.in	Tue Apr 14 16:28:59 2009
@@ -1,6 +1,6 @@
 [Desktop Entry]
 Encoding=UTF-8
-_Name=Update System
+_Name=Software Update
 _GenericName=Software Update Viewer
 _Comment=Update software installed on the system
 Icon=system-software-update

Modified: trunk/data/gpk-update-viewer.ui
==============================================================================
--- trunk/data/gpk-update-viewer.ui	(original)
+++ trunk/data/gpk-update-viewer.ui	Tue Apr 14 16:28:59 2009
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <interface>
-  <!-- interface-requires gtk+ 2.16 -->
+  <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkDialog" id="dialog_updates">
     <property name="border_width">5</property>
-    <property name="title" translatable="yes">Update System</property>
+    <property name="title" translatable="yes">Software Update</property>
     <property name="window_position">center</property>
     <property name="icon_name">software-update-available</property>
     <property name="type_hint">normal</property>
@@ -148,7 +148,6 @@
                       <object class="GtkTreeView" id="treeview_updates">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="rules_hint">True</property>
                       </object>
                     </child>
                   </object>
@@ -338,22 +337,8 @@
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="button_cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="button_close">
-                <property name="label">gtk-close</property>
+              <object class="GtkButton" id="button_quit">
+                <property name="label">gtk-quit</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="has_focus">True</property>
@@ -363,7 +348,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">2</property>
+                <property name="position">1</property>
               </packing>
             </child>
             <child>
@@ -378,7 +363,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">3</property>
+                <property name="position">2</property>
               </packing>
             </child>
           </object>
@@ -390,5 +375,10 @@
         </child>
       </object>
     </child>
+    <action-widgets>
+      <action-widget response="0">button_help</action-widget>
+      <action-widget response="0">button_quit</action-widget>
+      <action-widget response="0">button_install</action-widget>
+    </action-widgets>
   </object>
 </interface>

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Tue Apr 14 16:28:59 2009
@@ -22,24 +22,26 @@
 data/gpk-update-icon.desktop.in
 data/gpk-update-viewer.desktop.in
 data/gpk-update-viewer.ui
+python/packagekit/gtkwidgets.py
 src/gpk-application.c
 src/gpk-application-main.c
 src/gpk-backend-status.c
 src/gpk-check-update.c
-src/gpk-client.c
-src/gpk-client-chooser.c
-src/gpk-client-dialog.c
-src/gpk-client-eula.c
-src/gpk-client-run.c
-src/gpk-client-signature.c
-src/gpk-client-untrusted.c
 src/gpk-common.c
 src/gpk-consolekit.c
+src/gpk-dbus-task.c
+src/gpk-desktop.c
 src/gpk-dialog.c
 src/gpk-enum.c
 src/gpk-error.c
 src/gpk-firmware.c
 src/gpk-hardware.c
+src/gpk-helper-chooser.c
+src/gpk-helper-deps-install.c
+src/gpk-helper-deps-remove.c
+src/gpk-helper-media-change.c
+src/gpk-helper-run.c
+src/gpk-helper-untrusted.c
 src/gpk-inhibit.c
 src/gpk-install-catalog.c
 src/gpk-install-local-file.c
@@ -47,6 +49,7 @@
 src/gpk-install-package-name.c
 src/gpk-install-provide-file.c
 src/gpk-log.c
+src/gpk-modal-dialog.c
 src/gpk-prefs.c
 src/gpk-repo.c
 src/gpk-service-pack.c
@@ -54,6 +57,4 @@
 src/gpk-update-icon.c
 src/gpk-update-viewer.c
 src/gpk-watch.c
-src/gpk-desktop.c
-python/packagekit/gtkwidgets.py
 

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Tue Apr 14 16:28:59 2009
@@ -73,20 +73,24 @@
 	gpk-vendor.h					\
 	gpk-language.c					\
 	gpk-language.h					\
-	gpk-client.c					\
-	gpk-client.h					\
-	gpk-client-dialog.c				\
-	gpk-client-dialog.h				\
-	gpk-client-eula.c				\
-	gpk-client-eula.h				\
-	gpk-client-signature.c				\
-	gpk-client-signature.h				\
-	gpk-client-untrusted.c				\
-	gpk-client-untrusted.h				\
-	gpk-client-chooser.c				\
-	gpk-client-chooser.h				\
-	gpk-client-run.c				\
-	gpk-client-run.h				\
+	gpk-modal-dialog.c				\
+	gpk-modal-dialog.h				\
+	gpk-helper-repo-signature.c			\
+	gpk-helper-repo-signature.h			\
+	gpk-helper-eula.c				\
+	gpk-helper-eula.h				\
+	gpk-helper-run.c				\
+	gpk-helper-run.h				\
+	gpk-helper-deps-remove.c			\
+	gpk-helper-deps-remove.h			\
+	gpk-helper-deps-install.c			\
+	gpk-helper-deps-install.h			\
+	gpk-helper-untrusted.c				\
+	gpk-helper-untrusted.h				\
+	gpk-helper-chooser.c				\
+	gpk-helper-chooser.h				\
+	gpk-helper-media-change.c			\
+	gpk-helper-media-change.h			\
 	gpk-smart-icon.c				\
 	gpk-smart-icon.h				\
 	gpk-gnome.c					\
@@ -171,6 +175,8 @@
 	gpk-inhibit.h					\
 	gpk-dbus.c					\
 	gpk-dbus.h					\
+	gpk-dbus-task.c					\
+	gpk-dbus-task.h					\
 	$(shared_SOURCES)				\
 	$(NULL)
 
@@ -211,10 +217,6 @@
 
 gpk_update_viewer_SOURCES =				\
 	gpk-update-viewer.c				\
-	gpk-helper-repo-signature.c			\
-	gpk-helper-repo-signature.h			\
-	gpk-helper-eula.c				\
-	gpk-helper-eula.h				\
 	gpk-cell-renderer-size.c			\
 	gpk-cell-renderer-size.h			\
 	gpk-cell-renderer-info.c			\
@@ -292,6 +294,8 @@
 	egg-test.c					\
 	gpk-dbus.c					\
 	gpk-dbus.h					\
+	gpk-dbus-task.c					\
+	gpk-dbus-task.h					\
 	$(shared_SOURCES)				\
 	$(NULL)
 

Added: trunk/src/egg-markdown.c
==============================================================================
--- (empty file)
+++ trunk/src/egg-markdown.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,1286 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard 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 <string.h>
+#include <glib.h>
+
+#include "egg-debug.h"
+#include "egg-string.h"
+#include "egg-markdown.h"
+
+/*******************************************************************************
+ *
+ * This is a simple Markdown parser.
+ * It can output to Pango, HTML or plain text. The following limitations are
+ * already known, and properly deliberate:
+ *
+ * - No code section support
+ * - No ordered list support
+ * - No blockquote section support
+ * - No image support
+ * - No links or email support
+ * - No backslash escapes support
+ * - No HTML escaping support
+ * - Auto-escapes certain word patterns, like http://
+ *
+ * It does support the rest of the standard pretty well, although it's not
+ * been run against any conformance tests. The parsing is single pass, with
+ * a simple enumerated intepretor mode and a single line back-memory.
+ *
+ ******************************************************************************/
+
+static void     egg_markdown_finalize	(GObject		*object);
+
+#define EGG_MARKDOWN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_MARKDOWN, EggMarkdownPrivate))
+
+#define EGG_MARKDOWN_MAX_LINE_LENGTH	1024
+
+typedef enum {
+	EGG_MARKDOWN_MODE_BLANK,
+	EGG_MARKDOWN_MODE_RULE,
+	EGG_MARKDOWN_MODE_BULLETT,
+	EGG_MARKDOWN_MODE_PARA,
+	EGG_MARKDOWN_MODE_H1,
+	EGG_MARKDOWN_MODE_H2,
+	EGG_MARKDOWN_MODE_UNKNOWN
+} EggMarkdownMode;
+
+typedef struct {
+	const gchar *em_start;
+	const gchar *em_end;
+	const gchar *strong_start;
+	const gchar *strong_end;
+	const gchar *code_start;
+	const gchar *code_end;
+	const gchar *h1_start;
+	const gchar *h1_end;
+	const gchar *h2_start;
+	const gchar *h2_end;
+	const gchar *bullett_start;
+	const gchar *bullett_end;
+	const gchar *rule;
+} EggMarkdownTags;
+
+struct EggMarkdownPrivate
+{
+	EggMarkdownMode		 mode;
+	EggMarkdownTags		 tags;
+	EggMarkdownOutput	 output;
+	gint			 max_lines;
+	guint			 line_count;
+	gboolean		 smart_quoting;
+	gboolean		 escape;
+	gboolean		 autocode;
+	GString			*pending;
+	GString			*processed;
+};
+
+G_DEFINE_TYPE (EggMarkdown, egg_markdown, G_TYPE_OBJECT)
+
+/**
+ * egg_markdown_to_text_line_is_rule:
+ *
+ * Horizontal rules are created by placing three or more hyphens, asterisks,
+ * or underscores on a line by themselves.
+ * You may use spaces between the hyphens or asterisks.
+ **/
+static gboolean
+egg_markdown_to_text_line_is_rule (const gchar *line)
+{
+	guint i;
+	guint len;
+	guint count = 0;
+	gchar *copy = NULL;
+	gboolean ret = FALSE;
+
+	len = egg_strlen (line, EGG_MARKDOWN_MAX_LINE_LENGTH);
+	if (len == 0)
+		goto out;
+
+	/* replace non-rule chars with ~ */
+	copy = g_strdup (line);
+	g_strcanon (copy, "-*_ ", '~');
+	for (i=0; i<len; i++) {
+		if (copy[i] == '~')
+			goto out;
+		if (copy[i] != ' ')
+			count++;
+	}
+
+	/* if we matched, return true */
+	if (count >= 3)
+		ret = TRUE;
+out:
+	g_free (copy);
+	return ret;
+}
+
+/**
+ * egg_markdown_to_text_line_is_bullett:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_bullett (const gchar *line)
+{
+	return (g_str_has_prefix (line, "- ") ||
+		g_str_has_prefix (line, "* ") ||
+		g_str_has_prefix (line, "+ ") ||
+		g_str_has_prefix (line, " - ") ||
+		g_str_has_prefix (line, " * ") ||
+		g_str_has_prefix (line, " + "));
+}
+
+/**
+ * egg_markdown_to_text_line_is_header1:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_header1 (const gchar *line)
+{
+	return g_str_has_prefix (line, "# ");
+}
+
+/**
+ * egg_markdown_to_text_line_is_header2:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_header2 (const gchar *line)
+{
+	return g_str_has_prefix (line, "## ");
+}
+
+/**
+ * egg_markdown_to_text_line_is_header1_type2:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_header1_type2 (const gchar *line)
+{
+	return g_str_has_prefix (line, "===");
+}
+
+/**
+ * egg_markdown_to_text_line_is_header2_type2:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_header2_type2 (const gchar *line)
+{
+	return g_str_has_prefix (line, "---");
+}
+
+#if 0
+/**
+ * egg_markdown_to_text_line_is_code:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_code (const gchar *line)
+{
+	return (g_str_has_prefix (line, "    ") || g_str_has_prefix (line, "\t"));
+}
+
+/**
+ * egg_markdown_to_text_line_is_blockquote:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_blockquote (const gchar *line)
+{
+	return (g_str_has_prefix (line, "> "));
+}
+#endif
+
+/**
+ * egg_markdown_to_text_line_is_blank:
+ **/
+static gboolean
+egg_markdown_to_text_line_is_blank (const gchar *line)
+{
+	guint i;
+	guint len;
+	gboolean ret = FALSE;
+
+	len = egg_strlen (line, EGG_MARKDOWN_MAX_LINE_LENGTH);
+
+	/* a line with no characters is blank by definition */
+	if (len == 0) {
+		ret = TRUE;
+		goto out;
+	}
+
+	/* find if there are only space chars */
+	for (i=0; i<len; i++) {
+		if (line[i] != ' ' && line[i] != '\t')
+			goto out;
+	}
+
+	/* if we matched, return true */
+	ret = TRUE;
+out:
+	return ret;
+}
+
+/**
+ * egg_markdown_replace:
+ **/
+static gchar *
+egg_markdown_replace (const gchar *haystack, const gchar *needle, const gchar *replace)
+{
+	gchar *new;
+	gchar **split;
+
+	split = g_strsplit (haystack, needle, -1);
+	new = g_strjoinv (replace, split);
+	g_strfreev (split);
+
+	return new;
+}
+
+/**
+ * egg_markdown_strstr_spaces:
+ **/
+static gchar *
+egg_markdown_strstr_spaces (const gchar *haystack, const gchar *needle)
+{
+	gchar *found;
+	const gchar *haystack_new = haystack;
+
+retry:
+	/* don't find if surrounded by spaces */
+	found = strstr (haystack_new, needle);
+	if (found == NULL)
+		return NULL;
+
+	/* start of the string, always valid */
+	if (found == haystack)
+		return found;
+
+	/* end of the string, always valid */
+	if (*(found-1) == ' ' && *(found+1) == ' ') {
+		haystack_new = found+1;
+		goto retry;
+	}
+	return found;
+}
+
+/**
+ * egg_markdown_to_text_line_formatter:
+ **/
+static gchar *
+egg_markdown_to_text_line_formatter (const gchar *line, const gchar *formatter, const gchar *left, const gchar *right)
+{
+	guint len;
+	gchar *str1;
+	gchar *str2;
+	gchar *start = NULL;
+	gchar *middle = NULL;
+	gchar *end = NULL;
+	gchar *copy = NULL;
+	gchar *data = NULL;
+	gchar *temp;
+
+	/* needed to know for shifts */
+	len = egg_strlen (formatter, EGG_MARKDOWN_MAX_LINE_LENGTH);
+	if (len == 0)
+		goto out;
+
+	/* find sections */
+	copy = g_strdup (line);
+	str1 = egg_markdown_strstr_spaces (copy, formatter);
+	if (str1 != NULL) {
+		*str1 = '\0';
+		str2 = egg_markdown_strstr_spaces (str1+len, formatter);
+		if (str2 != NULL) {
+			*str2 = '\0';
+			middle = str1 + len;
+			start = copy;
+			end = str2 + len;
+		}
+	}
+
+	/* if we found, replace and keep looking for the same string */
+	if (start != NULL && middle != NULL && end != NULL) {
+		temp = g_strdup_printf ("%s%s%s%s%s", start, left, middle, right, end);
+		/* recursive */
+		data = egg_markdown_to_text_line_formatter (temp, formatter, left, right);
+		g_free (temp);
+	} else {
+		/* not found, keep return as-is */
+		data = g_strdup (line);
+	}
+out:
+	g_free (copy);
+	return data;
+}
+
+/**
+ * egg_markdown_to_text_line_format_sections:
+ **/
+static gchar *
+egg_markdown_to_text_line_format_sections (EggMarkdown *self, const gchar *line)
+{
+	gchar *data = g_strdup (line);
+	gchar *temp;
+
+	/* bold1 */
+	temp = data;
+	data = egg_markdown_to_text_line_formatter (temp, "**", self->priv->tags.strong_start, self->priv->tags.strong_end);
+	g_free (temp);
+
+	/* bold2 */
+	temp = data;
+	data = egg_markdown_to_text_line_formatter (temp, "__", self->priv->tags.strong_start, self->priv->tags.strong_end);
+	g_free (temp);
+
+	/* italic1 */
+	temp = data;
+	data = egg_markdown_to_text_line_formatter (temp, "*", self->priv->tags.em_start, self->priv->tags.em_end);
+	g_free (temp);
+
+	/* italic2 */
+	temp = data;
+	data = egg_markdown_to_text_line_formatter (temp, "_", self->priv->tags.em_start, self->priv->tags.em_end);
+	g_free (temp);
+
+	/* em-dash */
+	temp = data;
+	data = egg_markdown_replace (temp, " -- ", " â ");
+	g_free (temp);
+
+	/* smart quoting */
+	if (self->priv->smart_quoting) {
+		temp = data;
+		data = egg_markdown_to_text_line_formatter (temp, "\"", "â", "â");
+		g_free (temp);
+
+		temp = data;
+		data = egg_markdown_to_text_line_formatter (temp, "'", "â", "â");
+		g_free (temp);
+	}
+
+	return data;
+}
+
+/**
+ * egg_markdown_to_text_line_format:
+ **/
+static gchar *
+egg_markdown_to_text_line_format (EggMarkdown *self, const gchar *line)
+{
+	guint i;
+	gchar *text;
+	gboolean mode = FALSE;
+	gchar **codes;
+	GString *string;
+
+	/* optimise the trivial case where we don't have any code tags */
+	text = strstr (line, "`");
+	if (text == NULL) {
+		text = egg_markdown_to_text_line_format_sections (self, line);
+		goto out;
+	}
+
+	/* we want to parse the code sections without formatting */
+	codes = g_strsplit (line, "`", -1);
+	string = g_string_new ("");
+	for (i=0; codes[i] != NULL; i++) {
+		if (!mode) {
+			text = egg_markdown_to_text_line_format_sections (self, codes[i]);
+			g_string_append (string, text);
+			g_free (text);
+			mode = TRUE;
+		} else {
+			/* just append without formatting */
+			g_string_append (string, self->priv->tags.code_start);
+			g_string_append (string, codes[i]);
+			g_string_append (string, self->priv->tags.code_end);
+			mode = FALSE;
+		}
+	}
+	text = g_string_free (string, FALSE);
+out:
+	return text;
+}
+
+/**
+ * egg_markdown_add_pending:
+ **/
+static gboolean
+egg_markdown_add_pending (EggMarkdown *self, const gchar *line)
+{
+	gchar *copy;
+
+	/* would put us over the limit */
+	if (self->priv->line_count >= self->priv->max_lines)
+		return FALSE;
+
+	copy = g_strdup (line);
+
+	/* strip leading and trailing spaces */
+	g_strstrip (copy);
+
+	/* append */
+	g_string_append_printf (self->priv->pending, "%s ", copy);
+
+	g_free (copy);
+	return TRUE;
+}
+
+/**
+ * egg_markdown_add_pending_header:
+ **/
+static gboolean
+egg_markdown_add_pending_header (EggMarkdown *self, const gchar *line)
+{
+	gchar *copy;
+	gboolean ret;
+
+	/* strip trailing # */
+	copy = g_strdup (line);
+	g_strdelimit (copy, "#", ' ');
+	ret = egg_markdown_add_pending (self, copy);
+	g_free (copy);
+	return ret;
+}
+
+/**
+ * egg_markdown_word_is_code:
+ **/
+static gboolean
+egg_markdown_word_is_code (const gchar *text)
+{
+	if (g_str_has_prefix (text, "`"))
+		return FALSE;
+	if (g_str_has_suffix (text, "`"))
+		return FALSE;
+	if (g_str_has_prefix (text, "/"))
+		return TRUE;
+	if (g_str_has_prefix (text, "#"))
+		return TRUE;
+	if (g_str_has_prefix (text, "http://";))
+		return TRUE;
+	if (g_str_has_prefix (text, "https://";))
+		return TRUE;
+	if (g_str_has_prefix (text, "ftp://";))
+		return TRUE;
+	if (g_strrstr (text, ".patch") != NULL)
+		return TRUE;
+	if (g_strrstr (text, "()") != NULL)
+		return TRUE;
+	if (g_strrstr (text, "@") != NULL)
+		return TRUE;
+	return FALSE;
+}
+
+/**
+ * egg_markdown_word_auto_format_code:
+ **/
+static gchar *
+egg_markdown_word_auto_format_code (const gchar *text)
+{
+	guint i;
+	gchar *temp;
+	gchar **words;
+	gboolean ret = FALSE;
+
+	/* split sentance up with space */
+	words = g_strsplit (text, " ", -1);
+
+	/* search each word */
+	for (i=0; words[i] != NULL; i++) {
+		if (egg_markdown_word_is_code (words[i])) {
+			temp = g_strdup_printf ("`%s`", words[i]);
+			g_free (words[i]);
+			words[i] = temp;
+			ret = TRUE;
+		}
+	}
+
+	/* no replacements, so just return a copy */
+	if (!ret) {
+		temp = g_strdup (text);
+		goto out;
+	}
+
+	/* join the array back into a string */
+	temp = g_strjoinv (" ", words);
+out:
+	g_strfreev (words);
+	return temp;
+}
+
+/**
+ * egg_markdown_flush_pending:
+ **/
+static void
+egg_markdown_flush_pending (EggMarkdown *self)
+{
+	gchar *copy;
+	gchar *temp;
+
+	/* no data yet */
+	if (self->priv->mode == EGG_MARKDOWN_MODE_UNKNOWN)
+		return;
+
+	/* remove trailing spaces */
+	while (g_str_has_suffix (self->priv->pending->str, " "))
+		g_string_set_size (self->priv->pending, self->priv->pending->len - 1);
+
+	/* pango requires escaping */
+	copy = g_strdup (self->priv->pending->str);
+	if (!self->priv->escape && self->priv->output == EGG_MARKDOWN_OUTPUT_PANGO) {
+		g_strdelimit (copy, "<", '(');
+		g_strdelimit (copy, ">", ')');
+	}
+
+	/* check words for code */
+	if (self->priv->autocode &&
+	    (self->priv->mode == EGG_MARKDOWN_MODE_PARA ||
+	     self->priv->mode == EGG_MARKDOWN_MODE_BULLETT)) {
+		temp = egg_markdown_word_auto_format_code (copy);
+		g_free (copy);
+		copy = temp;
+	}
+
+	/* escape */
+	if (self->priv->escape) {
+		temp = g_markup_escape_text (copy, -1);
+		g_free (copy);
+		copy = temp;
+	}
+
+	/* do formatting */
+	temp = egg_markdown_to_text_line_format (self, copy);
+	if (self->priv->mode == EGG_MARKDOWN_MODE_BULLETT) {
+		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.bullett_start, temp, self->priv->tags.bullett_end);
+		self->priv->line_count++;
+	} else if (self->priv->mode == EGG_MARKDOWN_MODE_H1) {
+		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.h1_start, temp, self->priv->tags.h1_end);
+	} else if (self->priv->mode == EGG_MARKDOWN_MODE_H2) {
+		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.h2_start, temp, self->priv->tags.h2_end);
+	} else if (self->priv->mode == EGG_MARKDOWN_MODE_PARA ||
+		   self->priv->mode == EGG_MARKDOWN_MODE_RULE) {
+		g_string_append_printf (self->priv->processed, "%s\n", temp);
+		self->priv->line_count++;
+	}
+
+	egg_debug ("adding '%s'", temp);
+
+	/* clear */
+	g_string_truncate (self->priv->pending, 0);
+	g_free (copy);
+	g_free (temp);
+}
+
+/**
+ * egg_markdown_to_text_line_process:
+ **/
+static gboolean
+egg_markdown_to_text_line_process (EggMarkdown *self, const gchar *line)
+{
+	gboolean ret;
+
+	/* blank */
+	ret = egg_markdown_to_text_line_is_blank (line);
+	if (ret) {
+		egg_debug ("blank: '%s'", line);
+		egg_markdown_flush_pending (self);
+		/* a new line after a list is the end of list, not a gap */
+		if (self->priv->mode != EGG_MARKDOWN_MODE_BULLETT)
+			ret = egg_markdown_add_pending (self, "\n");
+		self->priv->mode = EGG_MARKDOWN_MODE_BLANK;
+		goto out;
+	}
+
+	/* header1_type2 */
+	ret = egg_markdown_to_text_line_is_header1_type2 (line);
+	if (ret) {
+		egg_debug ("header1_type2: '%s'", line);
+		if (self->priv->mode == EGG_MARKDOWN_MODE_PARA)
+			self->priv->mode = EGG_MARKDOWN_MODE_H1;
+		goto out;
+	}
+
+	/* header2_type2 */
+	ret = egg_markdown_to_text_line_is_header2_type2 (line);
+	if (ret) {
+		egg_debug ("header2_type2: '%s'", line);
+		if (self->priv->mode == EGG_MARKDOWN_MODE_PARA)
+			self->priv->mode = EGG_MARKDOWN_MODE_H2;
+		goto out;
+	}
+
+	/* rule */
+	ret = egg_markdown_to_text_line_is_rule (line);
+	if (ret) {
+		egg_debug ("rule: '%s'", line);
+		egg_markdown_flush_pending (self);
+		self->priv->mode = EGG_MARKDOWN_MODE_RULE;
+		ret = egg_markdown_add_pending (self, self->priv->tags.rule);
+		goto out;
+	}
+
+	/* bullett */
+	ret = egg_markdown_to_text_line_is_bullett (line);
+	if (ret) {
+		egg_debug ("bullett: '%s'", line);
+		egg_markdown_flush_pending (self);
+		self->priv->mode = EGG_MARKDOWN_MODE_BULLETT;
+		ret = egg_markdown_add_pending (self, &line[2]);
+		goto out;
+	}
+
+	/* header1 */
+	ret = egg_markdown_to_text_line_is_header1 (line);
+	if (ret) {
+		egg_debug ("header1: '%s'", line);
+		egg_markdown_flush_pending (self);
+		self->priv->mode = EGG_MARKDOWN_MODE_H1;
+		ret = egg_markdown_add_pending_header (self, &line[2]);
+		goto out;
+	}
+
+	/* header2 */
+	ret = egg_markdown_to_text_line_is_header2 (line);
+	if (ret) {
+		egg_debug ("header2: '%s'", line);
+		egg_markdown_flush_pending (self);
+		self->priv->mode = EGG_MARKDOWN_MODE_H2;
+		ret = egg_markdown_add_pending_header (self, &line[3]);
+		goto out;
+	}
+
+	/* paragraph */
+	if (self->priv->mode == EGG_MARKDOWN_MODE_BLANK || self->priv->mode == EGG_MARKDOWN_MODE_UNKNOWN) {
+		egg_markdown_flush_pending (self);
+		self->priv->mode = EGG_MARKDOWN_MODE_PARA;
+	}
+
+	/* add to pending */
+	egg_debug ("continue: '%s'", line);
+	ret = egg_markdown_add_pending (self, line);
+out:
+	/* if we failed to add, we don't know the mode */
+	if (!ret)
+		self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN;
+	return ret;
+}
+
+/**
+ * egg_markdown_set_output:
+ **/
+gboolean
+egg_markdown_set_output (EggMarkdown *self, EggMarkdownOutput output)
+{
+	gboolean ret = TRUE;
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE);
+
+	/* PangoMarkup */
+	if (output == EGG_MARKDOWN_OUTPUT_PANGO) {
+		self->priv->tags.em_start = "<i>";
+		self->priv->tags.em_end = "</i>";
+		self->priv->tags.strong_start = "<b>";
+		self->priv->tags.strong_end = "</b>";
+		self->priv->tags.code_start = "<tt>";
+		self->priv->tags.code_end = "</tt>";
+		self->priv->tags.h1_start = "<big>";
+		self->priv->tags.h1_end = "</big>";
+		self->priv->tags.h2_start = "<b>";
+		self->priv->tags.h2_end = "</b>";
+		self->priv->tags.bullett_start = "â ";
+		self->priv->tags.bullett_end = "";
+		self->priv->tags.rule = "ââââââââââââââââââââââ\n";
+
+	/* XHTML */
+	} else if (output == EGG_MARKDOWN_OUTPUT_HTML) {
+		self->priv->tags.em_start = "<em>";
+		self->priv->tags.em_end = "<em>";
+		self->priv->tags.strong_start = "<strong>";
+		self->priv->tags.strong_end = "</strong>";
+		self->priv->tags.code_start = "<code>";
+		self->priv->tags.code_end = "</code>";
+		self->priv->tags.h1_start = "<h1>";
+		self->priv->tags.h1_end = "</h1>";
+		self->priv->tags.h2_start = "<h2>";
+		self->priv->tags.h2_end = "</h2>";
+		self->priv->tags.bullett_start = "<li>";
+		self->priv->tags.bullett_end = "</li>";
+		self->priv->tags.rule = "<hr>";
+
+	/* plain text */
+	} else if (output == EGG_MARKDOWN_OUTPUT_TEXT) {
+		self->priv->tags.em_start = "";
+		self->priv->tags.em_end = "";
+		self->priv->tags.strong_start = "";
+		self->priv->tags.strong_end = "";
+		self->priv->tags.code_start = "";
+		self->priv->tags.code_end = "";
+		self->priv->tags.h1_start = "[";
+		self->priv->tags.h1_end = "]";
+		self->priv->tags.h2_start = "-";
+		self->priv->tags.h2_end = "-";
+		self->priv->tags.bullett_start = "* ";
+		self->priv->tags.bullett_end = "";
+		self->priv->tags.rule = " ----- \n";
+
+	/* unknown */
+	} else {
+		egg_warning ("unknown output enum");
+		ret = FALSE;
+	}
+
+	/* save if valid */
+	if (ret)
+		self->priv->output = output;
+	return ret;
+}
+
+/**
+ * egg_markdown_set_max_lines:
+ **/
+gboolean
+egg_markdown_set_max_lines (EggMarkdown *self, gint max_lines)
+{
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE);
+	self->priv->max_lines = max_lines;
+	return TRUE;
+}
+
+/**
+ * egg_markdown_set_smart_quoting:
+ **/
+gboolean
+egg_markdown_set_smart_quoting (EggMarkdown *self, gboolean smart_quoting)
+{
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE);
+	self->priv->smart_quoting = smart_quoting;
+	return TRUE;
+}
+
+/**
+ * egg_markdown_set_escape:
+ **/
+gboolean
+egg_markdown_set_escape (EggMarkdown *self, gboolean escape)
+{
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE);
+	self->priv->escape = escape;
+	return TRUE;
+}
+
+/**
+ * egg_markdown_set_autocode:
+ **/
+gboolean
+egg_markdown_set_autocode (EggMarkdown *self, gboolean autocode)
+{
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE);
+	self->priv->autocode = autocode;
+	return TRUE;
+}
+
+/**
+ * egg_markdown_parse:
+ **/
+gchar *
+egg_markdown_parse (EggMarkdown *self, const gchar *markdown)
+{
+	gchar **lines;
+	guint i;
+	guint len;
+	gchar *temp;
+	gboolean ret;
+
+	g_return_val_if_fail (EGG_IS_MARKDOWN (self), NULL);
+	g_return_val_if_fail (self->priv->output != EGG_MARKDOWN_OUTPUT_UNKNOWN, NULL);
+
+	egg_debug ("input='%s'", markdown);
+
+	/* process */
+	self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN;
+	self->priv->line_count = 0;
+	g_string_truncate (self->priv->pending, 0);
+	g_string_truncate (self->priv->processed, 0);
+	lines = g_strsplit (markdown, "\n", -1);
+	len = g_strv_length (lines);
+
+	/* process each line */
+	for (i=0; i<len; i++) {
+		ret = egg_markdown_to_text_line_process (self, lines[i]);
+		if (!ret)
+			break;
+	}
+	g_strfreev (lines);
+	egg_markdown_flush_pending (self);
+
+	/* remove trailing \n */
+	while (g_str_has_suffix (self->priv->processed->str, "\n"))
+		g_string_set_size (self->priv->processed, self->priv->processed->len - 1);
+
+	/* get a copy */
+	temp = g_strdup (self->priv->processed->str);
+	g_string_truncate (self->priv->pending, 0);
+	g_string_truncate (self->priv->processed, 0);
+
+	egg_debug ("output='%s'", temp);
+
+	return temp;
+}
+
+/**
+ * egg_markdown_class_init:
+ * @klass: The EggMarkdownClass
+ **/
+static void
+egg_markdown_class_init (EggMarkdownClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = egg_markdown_finalize;
+	g_type_class_add_private (klass, sizeof (EggMarkdownPrivate));
+}
+
+/**
+ * egg_markdown_init:
+ **/
+static void
+egg_markdown_init (EggMarkdown *self)
+{
+	self->priv = EGG_MARKDOWN_GET_PRIVATE (self);
+
+	self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN;
+	self->priv->output = EGG_MARKDOWN_OUTPUT_UNKNOWN;
+	self->priv->pending = g_string_new ("");
+	self->priv->processed = g_string_new ("");
+	self->priv->max_lines = -1;
+	self->priv->smart_quoting = FALSE;
+	self->priv->escape = FALSE;
+	self->priv->autocode = FALSE;
+}
+
+/**
+ * egg_markdown_finalize:
+ * @object: The object to finalize
+ **/
+static void
+egg_markdown_finalize (GObject *object)
+{
+	EggMarkdown *self;
+
+	g_return_if_fail (EGG_IS_MARKDOWN (object));
+
+	self = EGG_MARKDOWN (object);
+
+	g_return_if_fail (self->priv != NULL);
+	g_string_free (self->priv->pending, TRUE);
+	g_string_free (self->priv->processed, TRUE);
+
+	G_OBJECT_CLASS (egg_markdown_parent_class)->finalize (object);
+}
+
+/**
+ * egg_markdown_new:
+ *
+ * Return value: a new EggMarkdown object.
+ **/
+EggMarkdown *
+egg_markdown_new (void)
+{
+	EggMarkdown *self;
+	self = g_object_new (EGG_TYPE_MARKDOWN, NULL);
+	return EGG_MARKDOWN (self);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+egg_markdown_test (EggTest *test)
+{
+	EggMarkdown *self;
+	gchar *text;
+	gboolean ret;
+	const gchar *markdown;
+	const gchar *markdown_expected;
+
+	if (!egg_test_start (test, "EggMarkdown"))
+		return;
+
+	/************************************************************
+	 ****************        line_is_rule          **************
+	 ************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("* * *");
+	egg_test_title_assert (test, "is rule (1)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("***");
+	egg_test_title_assert (test, "is rule (2)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("*****");
+	egg_test_title_assert (test, "is rule (3)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("- - -");
+	egg_test_title_assert (test, "is rule (4)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("---------------------------------------");
+	egg_test_title_assert (test, "is rule (5)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("");
+	egg_test_title_assert (test, "is rule (blank)", !ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("richard hughes");
+	egg_test_title_assert (test, "is rule (text)", !ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_rule ("- richard-hughes");
+	egg_test_title_assert (test, "is rule (bullet)", !ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_blank ("");
+	egg_test_title_assert (test, "is blank (blank)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_blank (" \t ");
+	egg_test_title_assert (test, "is blank (mix)", ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_blank ("richard hughes");
+	egg_test_title_assert (test, "is blank (name)", !ret);
+
+	/************************************************************/
+	ret = egg_markdown_to_text_line_is_blank ("ccccccccc");
+	egg_test_title_assert (test, "is blank (full)", !ret);
+
+
+	/************************************************************
+	 ****************           replace            **************
+	 ************************************************************/
+	text = egg_markdown_replace ("summary -- really -- sure!", " -- ", " â ");
+	egg_test_title (test, "replace (multiple)");
+	if (egg_strequal (text, "summary â really â sure!"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************
+	 ****************          formatter           **************
+	 ************************************************************/
+	text = egg_markdown_to_text_line_formatter ("**is important** text", "**", "<b>", "</b>");
+	egg_test_title (test, "formatter (left)");
+	if (egg_strequal (text, "<b>is important</b> text"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("this is **important**", "**", "<b>", "</b>");
+	egg_test_title (test, "formatter (right)");
+	if (egg_strequal (text, "this is <b>important</b>"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("**important**", "**", "<b>", "</b>");
+	egg_test_title (test, "formatter (only)");
+	if (egg_strequal (text, "<b>important</b>"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("***important***", "**", "<b>", "</b>");
+	egg_test_title (test, "formatter (only)");
+	if (egg_strequal (text, "<b>*important</b>*"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("I guess * this is * not bold", "*", "<i>", "</i>");
+	egg_test_title (test, "formatter (with spaces)");
+	if (egg_strequal (text, "I guess * this is * not bold"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("this **is important** text in **several** places", "**", "<b>", "</b>");
+	egg_test_title (test, "formatter (middle, multiple)");
+	if (egg_strequal (text, "this <b>is important</b> text in <b>several</b> places"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_word_auto_format_code ("this is http://www.hughsie.com/with_spaces_in_url inline link");
+	egg_test_title (test, "auto formatter (url)");
+	if (egg_strequal (text, "this is `http://www.hughsie.com/with_spaces_in_url` inline link"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("this was \"triffic\" it was", "\"", "â", "â");
+	egg_test_title (test, "formatter (quotes)");
+	if (egg_strequal (text, "this was âtrifficâ it was"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************/
+	text = egg_markdown_to_text_line_formatter ("This isn't a present", "'", "â", "â");
+	egg_test_title (test, "formatter (one quote)");
+	if (egg_strequal (text, "This isn't a present"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got %s", text);
+	g_free (text);
+
+	/************************************************************
+	 ****************          markdown            **************
+	 ************************************************************/
+	egg_test_title (test, "get EggMarkdown object");
+	self = egg_markdown_new ();
+	egg_test_assert (test, self != NULL);
+
+	/************************************************************/
+	ret = egg_markdown_set_output (self, EGG_MARKDOWN_OUTPUT_PANGO);
+	egg_test_title_assert (test, "set pango output", ret);
+
+	/************************************************************/
+	markdown = "OEMs\n"
+		   "====\n"
+		   " - Bullett\n";
+	markdown_expected =
+		   "<big>OEMs</big>\n"
+		   "â Bullett";
+	egg_test_title (test, "markdown (type2 header)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+
+	/************************************************************/
+	markdown = "this is http://www.hughsie.com/with_spaces_in_url inline link\n";
+	markdown_expected = "this is <tt>http://www.hughsie.com/with_spaces_in_url</tt> inline link";
+	egg_test_title (test, "markdown (autocode)");
+	egg_markdown_set_autocode (self, TRUE);
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	markdown = "*** This software is currently in alpha state ***\n";
+	markdown_expected = "<b><i> This software is currently in alpha state </b></i>";
+	egg_test_title (test, "markdown some invalid header");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	markdown = " - This is a *very*\n"
+		   "   short paragraph\n"
+		   "   that is not usual.\n"
+		   " - Another";
+	markdown_expected =
+		   "â This is a <i>very</i> short paragraph that is not usual.\n"
+		   "â Another";
+	egg_test_title (test, "markdown (complex1)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	markdown = "*  This is a *very*\n"
+		   "   short paragraph\n"
+		   "   that is not usual.\n"
+		   "*  This is the second\n"
+		   "   bullett point.\n"
+		   "*  And the third.\n"
+		   " \n"
+		   "* * *\n"
+		   " \n"
+		   "Paragraph one\n"
+		   "isn't __very__ long at all.\n"
+		   "\n"
+		   "Paragraph two\n"
+		   "isn't much better.";
+	markdown_expected =
+		   "â This is a <i>very</i> short paragraph that is not usual.\n"
+		   "â This is the second bullett point.\n"
+		   "â And the third.\n"
+		   "ââââââââââââââââââââââ\n"
+		   "Paragraph one isn't <b>very</b> long at all.\n"
+		   "Paragraph two isn't much better.";
+	egg_test_title (test, "markdown (complex1)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	markdown = "This is a spec file description or\n"
+		   "an **update** description in bohdi.\n"
+		   "\n"
+		   "* * *\n"
+		   "# Big title #\n"
+		   "\n"
+		   "The *following* things 'were' fixed:\n"
+		   "- Fix `dave`\n"
+		   "* Fubar update because of \"security\"\n";
+	markdown_expected =
+		   "This is a spec file description or an <b>update</b> description in bohdi.\n"
+		   "ââââââââââââââââââââââ\n"
+		   "<big>Big title</big>\n"
+		   "The <i>following</i> things 'were' fixed:\n"
+		   "â Fix <tt>dave</tt>\n"
+		   "â Fubar update because of \"security\"";
+	egg_test_title (test, "markdown (complex2)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	markdown = "* list seporated with spaces -\n"
+		   "  first item\n"
+		   "\n"
+		   "* second item\n"
+		   "\n"
+		   "* third item\n";
+	markdown_expected =
+		   "â list seporated with spaces - first item\n"
+		   "â second item\n"
+		   "â third item";
+	egg_test_title (test, "markdown (list with spaces)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	ret = egg_markdown_set_max_lines (self, 1);
+	egg_test_title_assert (test, "set max_lines", ret);
+
+	/************************************************************/
+	markdown = "* list seporated with spaces -\n"
+		   "  first item\n"
+		   "* second item\n";
+	markdown_expected =
+		   "â list seporated with spaces - first item";
+	egg_test_title (test, "markdown (one line limit)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	ret = egg_markdown_set_max_lines (self, 1);
+	egg_test_title_assert (test, "set max_lines", ret);
+
+	/************************************************************/
+	markdown = "* list & spaces";
+	markdown_expected =
+		   "â list & spaces";
+	egg_test_title (test, "markdown (escaping)");
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	/************************************************************/
+	egg_test_title (test, "markdown (free text)");
+	text = egg_markdown_parse (self, "This isn't a present");
+	if (egg_strequal (text, "This isn't a present"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s'", text);
+	g_free (text);
+
+	/************************************************************/
+	markdown = "*Thu Mar 12 12:00:00 2009* Dan Walsh <dwalsh redhat com> - 2.0.79-1\n"
+		   "- Update to upstream \n"
+		   " * Netlink socket handoff patch from Adam Jackson.\n"
+		   " * AVC caching of compute_create results by Eric Paris.\n"
+		   "\n"
+		   "*Tue Mar 10 12:00:00 2009* Dan Walsh <dwalsh redhat com> - 2.0.78-5\n"
+		   "- Add patch from ajax to accellerate X SELinux \n"
+		   "- Update eparis patch\n";
+	markdown_expected =
+		   "<i>Thu Mar 12 12:00:00 2009</i> Dan Walsh <tt>&lt;dwalsh redhat com&gt;</tt> - 2.0.79-1\n"
+		   "â Update to upstream\n"
+		   "â Netlink socket handoff patch from Adam Jackson.\n"
+		   "â AVC caching of compute_create results by Eric Paris.\n"
+		   "<i>Tue Mar 10 12:00:00 2009</i> Dan Walsh <tt>&lt;dwalsh redhat com&gt;</tt> - 2.0.78-5\n"
+		   "â Add patch from ajax to accellerate X SELinux\n"
+		   "â Update eparis patch";
+	egg_test_title (test, "markdown (end of bullett)");
+	egg_markdown_set_escape (self, TRUE);
+	ret = egg_markdown_set_max_lines (self, 1024);
+	text = egg_markdown_parse (self, markdown);
+	if (egg_strequal (text, markdown_expected))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected);
+	g_free (text);
+
+	g_object_unref (self);
+
+	egg_test_end (test);
+}
+#endif
+

Added: trunk/src/egg-markdown.h
==============================================================================
--- (empty file)
+++ trunk/src/egg-markdown.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard 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 __EGG_MARKDOWN_H
+#define __EGG_MARKDOWN_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_MARKDOWN		(egg_markdown_get_type ())
+#define EGG_MARKDOWN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_MARKDOWN, EggMarkdown))
+#define EGG_MARKDOWN_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_MARKDOWN, EggMarkdownClass))
+#define EGG_IS_MARKDOWN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_MARKDOWN))
+#define EGG_IS_MARKDOWN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_MARKDOWN))
+#define EGG_MARKDOWN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_MARKDOWN, EggMarkdownClass))
+#define EGG_MARKDOWN_ERROR		(egg_markdown_error_quark ())
+#define EGG_MARKDOWN_TYPE_ERROR	(egg_markdown_error_get_type ())
+
+typedef struct EggMarkdownPrivate EggMarkdownPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 EggMarkdownPrivate	*priv;
+} EggMarkdown;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+	void		(* active_changed)		(EggMarkdown	*self,
+							 gboolean	 active);
+} EggMarkdownClass;
+
+typedef enum {
+	EGG_MARKDOWN_OUTPUT_TEXT,
+	EGG_MARKDOWN_OUTPUT_PANGO,
+	EGG_MARKDOWN_OUTPUT_HTML,
+	EGG_MARKDOWN_OUTPUT_UNKNOWN
+} EggMarkdownOutput;
+
+GType		 egg_markdown_get_type	  		(void);
+EggMarkdown	*egg_markdown_new			(void);
+gboolean	 egg_markdown_set_output		(EggMarkdown		*self,
+							 EggMarkdownOutput	 output);
+gboolean	 egg_markdown_set_max_lines		(EggMarkdown		*self,
+							 gint			 max_lines);
+gboolean	 egg_markdown_set_smart_quoting		(EggMarkdown		*self,
+							 gboolean		 smart_quoting);
+gboolean	 egg_markdown_set_escape		(EggMarkdown		*self,
+							 gboolean		 escape);
+gboolean	 egg_markdown_set_autocode		(EggMarkdown		*self,
+							 gboolean		 autocode);
+gchar		*egg_markdown_parse			(EggMarkdown		*self,
+							 const gchar		*text);
+
+G_END_DECLS
+
+#endif /* __EGG_MARKDOWN_H */
+

Modified: trunk/src/gpk-application.c
==============================================================================
--- trunk/src/gpk-application.c	(original)
+++ trunk/src/gpk-application.c	Tue Apr 14 16:28:59 2009
@@ -35,7 +35,6 @@
 #include "egg-string.h"
 #include "egg-markdown.h"
 
-#include "gpk-client.h"
 #include "gpk-common.h"
 #include "gpk-gnome.h"
 #include "gpk-error.h"
@@ -43,10 +42,14 @@
 #include "gpk-application.h"
 #include "gpk-animated-icon.h"
 #include "gpk-dialog.h"
-#include "gpk-client-run.h"
-#include "gpk-client-chooser.h"
 #include "gpk-cell-renderer-uri.h"
 #include "gpk-desktop.h"
+#include "gpk-helper-repo-signature.h"
+#include "gpk-helper-eula.h"
+#include "gpk-helper-run.h"
+#include "gpk-helper-deps-remove.h"
+#include "gpk-helper-deps-install.h"
+#include "gpk-helper-media-change.h"
 
 static void     gpk_application_finalize   (GObject	    *object);
 
@@ -82,11 +85,8 @@
 	GtkListStore		*details_store;
 	EggMarkdown		*markdown;
 	PkControl		*control;
-	PkClient		*client_search;
-	PkClient		*client_action;
-	PkClient		*client_details;
-	PkClient		*client_files;
-	GpkClient		*gclient;
+	PkClient		*client_primary;
+	PkClient		*client_secondary;
 	PkConnection		*pconnection;
 	PkDesktop		*desktop;
 	gchar			*package;
@@ -105,6 +105,13 @@
 	PkActionMode		 action;
 	GPtrArray		*package_list;
 	GtkWidget		*image_status;
+	GpkHelperRepoSignature	*helper_repo_signature;
+	GpkHelperEula		*helper_eula;
+	GpkHelperRun		*helper_run;
+	GpkHelperDepsRemove	*helper_deps_remove;
+	GpkHelperDepsInstall	*helper_deps_install;
+	GpkHelperMediaChange	*helper_media_change;
+	gboolean		 dep_check_info_only;
 };
 
 enum {
@@ -149,7 +156,8 @@
 
 G_DEFINE_TYPE (GpkApplication, gpk_application, G_TYPE_OBJECT)
 
-static gboolean gpk_application_refresh_search_results (GpkApplication *application);
+static void gpk_application_categories_finished (GpkApplication *application);
+static gboolean gpk_application_perform_search (GpkApplication *application);
 
 /**
  * gpk_application_class_init:
@@ -237,29 +245,6 @@
 }
 
 /**
- * gpk_application_set_find_cancel_buttons:
- **/
-static void
-gpk_application_set_find_cancel_buttons (GpkApplication *application, gboolean find)
-{
-	GtkWidget *widget;
-
-	/* if we can't do it, then just make the button insensitive */
-	if (!pk_bitfield_contain (application->priv->roles, PK_ROLE_ENUM_CANCEL)) {
-		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "button_cancel"));
-		gtk_widget_set_sensitive (widget, FALSE);
-	}
-
-	/* which tab to enable? */
-	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "notebook_search_cancel"));
-	if (find) {
-		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0);
-	} else {
-		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1);
-	}
-}
-
-/**
  * gpk_application_set_text_buffer:
  **/
 static void
@@ -498,50 +483,30 @@
 static void
 gpk_application_menu_files_cb (GtkAction *action, GpkApplication *application)
 {
-	GPtrArray *array;
+	gboolean ret;
 	GError *error = NULL;
-	gchar **files;
-	gchar *title;
-	GtkWindow *window;
-	GtkWidget *dialog;
-	PkPackageId *id;
+	gchar **package_ids = NULL;
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
-	gpk_client_set_interaction (application->priv->gclient, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
-	files = gpk_client_get_file_list (application->priv->gclient, application->priv->package, &error);
-	if (files == NULL) {
-		egg_warning ("could not get file list: %s", error->message);
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
 		g_error_free (error);
-		return;
+		goto out;
 	}
 
-	/* convert to pointer array */
-	array = pk_strv_to_ptr_array (files);
-	g_ptr_array_sort (array, (GCompareFunc) gpk_application_strcmp_indirect);
-
-	/* title */
-	id = pk_package_id_new_from_string (application->priv->package);
-	/* TRANSLATORS: title: how many files are installed by the application */
-	title = g_strdup_printf (ngettext ("%i file installed by %s",
-					   "%i files installed by %s",
-					   array->len), array->len, id->name);
-
-	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
-	dialog = gtk_message_dialog_new (window, GTK_DIALOG_DESTROY_WITH_PARENT,
-					 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
-	gpk_dialog_embed_file_list_widget (GTK_DIALOG (dialog), array);
-	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
-	gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 250);
-
-	gtk_dialog_run (GTK_DIALOG (dialog));
-	gtk_widget_destroy (GTK_WIDGET (dialog));
-
-	g_free (title);
-	g_ptr_array_foreach (array, (GFunc) g_free, NULL);
-	g_ptr_array_free (array, TRUE);
-	g_strfreev (files);
-	pk_package_id_free (id);
+	/* set correct view */
+	package_ids = pk_package_ids_from_id (application->priv->package);
+	ret = pk_client_get_files (application->priv->client_primary, package_ids, &error);
+	if (!ret) {
+		egg_warning ("cannot get file lists for %s: %s", application->priv->package, error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
 }
 
 /**
@@ -621,14 +586,11 @@
 static void
 gpk_application_menu_run_cb (GtkAction *action, GpkApplication *application)
 {
-	gchar *exec;
-	GError *error = NULL;
 	gchar **package_ids;
 	GtkTreeView *treeview;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	GtkTreeSelection *selection;
-	GtkWindow *window;
 	PkBitfield state;
 	gboolean ret;
 	gchar *package_id = NULL;
@@ -651,16 +613,7 @@
 	if (pk_bitfield_contain (state, GPK_STATE_INSTALLED)) {
 		/* run this single package id */
 		package_ids = pk_package_ids_from_id (package_id);
-		window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
-		exec = gpk_client_run_show (window, package_ids);
-		if (exec != NULL) {
-			ret = g_spawn_command_line_async (exec, &error);
-			if (!ret) {
-				egg_warning ("failed to run: %s", error->message);
-				g_error_free (error);
-			}
-		}
-		g_free (exec);
+		gpk_helper_run_show (application->priv->helper_run, package_ids);
 		g_strfreev (package_ids);
 	}
 	g_free (package_id);
@@ -674,74 +627,28 @@
 {
 	GError *error = NULL;
 	gboolean ret;
-	PkPackageList *list;
-	GtkWidget *widget;
-	GtkWindow *window;
-	gchar **package_ids;
+	gchar **package_ids = NULL;
 
 	/* cancel any previous request */
-	ret = pk_client_reset (application->priv->client_files, &error);
+	ret = pk_client_reset (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to cancel, and adding to queue: %s", error->message);
 		g_error_free (error);
-		return;
+		goto out;
 	}
 
 	/* get the requires */
-	pk_client_set_synchronous (application->priv->client_files, TRUE, NULL);
 	package_ids = pk_package_ids_from_id (application->priv->package);
-	ret = pk_client_get_requires (application->priv->client_files, PK_FILTER_ENUM_NONE,
+	application->priv->dep_check_info_only = TRUE;
+	ret = pk_client_get_requires (application->priv->client_primary, PK_FILTER_ENUM_NONE,
 				      package_ids, TRUE, &error);
-	pk_client_set_synchronous (application->priv->client_files, FALSE, NULL);
-
 	if (!ret) {
 		egg_warning ("failed to get requires: %s", error->message);
 		g_error_free (error);
-		return;
-	}
-
-	list = pk_client_get_package_list (application->priv->client_files);
-	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
-	if (pk_package_list_get_size (list) == 0) {
-		gpk_error_dialog_modal (window,
-					/* TRANSLATORS: no packages returned */
-					_("No packages"),
-					/* TRANSLATORS: this package is not required by any others */
-					_("No other packages require this package"), NULL);
-	} else {
-		gchar *name;
-		gchar *title;
-		gchar *message;
-		guint length;
-		GtkWidget *dialog;
-
-		length = pk_package_list_get_size (list);
-		name = gpk_dialog_package_id_name_join_locale (package_ids);
-		/* TRANSLATORS: title: how many packages require this package */
-		title = g_strdup_printf (ngettext ("%i package requires %s",
-						   "%i packages require %s",
-						   length), length, name);
-
-		/* TRANSLATORS: show a list of packages for the package */
-		message = g_strdup_printf (ngettext ("Packages listed below require %s to function correctly.",
-						     "Packages listed below require %s to function correctly.",
-						     length), name);
-
-		dialog = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_DESTROY_WITH_PARENT,
-						 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
-		gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
-		gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), list);
-
-		gtk_dialog_run (GTK_DIALOG (dialog));
-		gtk_widget_destroy (GTK_WIDGET (dialog));
-
-		g_free (name);
-		g_free (title);
-		g_free (message);
+		goto out;
 	}
-
+out:
 	g_strfreev (package_ids);
-	g_object_unref (list);
 }
 
 /**
@@ -752,74 +659,28 @@
 {
 	GError *error = NULL;
 	gboolean ret;
-	PkPackageList *list;
-	GtkWidget *widget;
-	GtkWindow *window;
-	gchar **package_ids;
+	gchar **package_ids = NULL;
 
 	/* cancel any previous request */
-	ret = pk_client_reset (application->priv->client_files, &error);
+	ret = pk_client_reset (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to cancel, and adding to queue: %s", error->message);
 		g_error_free (error);
-		return;
+		goto out;
 	}
 
 	/* get the depends */
-	pk_client_set_synchronous (application->priv->client_files, TRUE, NULL);
 	package_ids = pk_package_ids_from_id (application->priv->package);
-	ret = pk_client_get_depends (application->priv->client_files, PK_FILTER_ENUM_NONE,
+	application->priv->dep_check_info_only = TRUE;
+	ret = pk_client_get_depends (application->priv->client_primary, PK_FILTER_ENUM_NONE,
 				     package_ids, TRUE, &error);
-	pk_client_set_synchronous (application->priv->client_files, FALSE, NULL);
-
 	if (!ret) {
 		egg_warning ("failed to get depends: %s", error->message);
 		g_error_free (error);
-		return;
-	}
-
-	list = pk_client_get_package_list (application->priv->client_files);
-	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
-	if (pk_package_list_get_size (list) == 0) {
-		gpk_error_dialog_modal (window,
-					/* TRANSLATORS: no packages returned */
-					_("No packages"),
-					/* TRANSLATORS: this package does not depend on any others */
-					_("This package does not depends on any others"), NULL);
-	} else {
-		gchar *name;
-		gchar *title;
-		gchar *message;
-		guint length;
-		GtkWidget *dialog;
-
-		length = pk_package_list_get_size (list);
-		name = gpk_dialog_package_id_name_join_locale (package_ids);
-		/* TRANSLATORS: title: show the number of other packages we depend on */
-		title = g_strdup_printf (ngettext ("%i additional package is required for %s",
-						   "%i additional packages are required for %s",
-						   length), length, name);
-
-		/* TRANSLATORS: message: show the list of dependant packages for this package */
-		message = g_strdup_printf (ngettext ("Packages listed below are required for %s to function correctly.",
-						     "Packages listed below are required for %s to function correctly.",
-						     length), name);
-
-		dialog = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_DESTROY_WITH_PARENT,
-						 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
-		gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
-		gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), list);
-
-		gtk_dialog_run (GTK_DIALOG (dialog));
-		gtk_widget_destroy (GTK_WIDGET (dialog));
-
-		g_free (name);
-		g_free (title);
-		g_free (message);
+		goto out;
 	}
-
+out:
 	g_strfreev (package_ids);
-	g_object_unref (list);
 }
 
 /**
@@ -1064,11 +925,17 @@
 	gboolean enabled;
 	PkBitfield state = 0;
 	static guint package_cnt = 0;
+	PkRoleEnum role;
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
 	egg_debug ("package = %s:%s:%s", pk_info_enum_to_text (obj->info), obj->id->name, obj->summary);
 
+	/* ignore not search data */
+	pk_client_get_role (client, &role, NULL, NULL);
+	if (role == PK_ROLE_ENUM_GET_DEPENDS || role == PK_ROLE_ENUM_GET_REQUIRES)
+		return;
+
 	/* ignore progress */
 	if (obj->info != PK_INFO_ENUM_INSTALLED && obj->info != PK_INFO_ENUM_AVAILABLE &&
 	    obj->info != PK_INFO_ENUM_COLLECTION_INSTALLED && obj->info != PK_INFO_ENUM_COLLECTION_AVAILABLE)
@@ -1149,42 +1016,20 @@
 	if (code == PK_ERROR_ENUM_TRANSACTION_CANCELLED)
 		return;
 
+	/* ignore the ones we can handle */
+	if (code == PK_ERROR_ENUM_GPG_FAILURE ||
+	    code == PK_ERROR_ENUM_NO_LICENSE_AGREEMENT ||
+	    code == PK_ERROR_ENUM_MEDIA_CHANGE_REQUIRED) {
+		egg_debug ("error ignored as we're handling %s\n%s", pk_error_enum_to_text (code), details);
+		return;
+	}
+
 	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
 	gpk_error_dialog_modal (window, gpk_error_enum_to_localised_text (code),
 				gpk_error_enum_to_localised_message (code), details);
 }
 
 /**
- * gpk_application_refresh_search_results:
- **/
-static gboolean
-gpk_application_refresh_search_results (GpkApplication *application)
-{
-	gboolean ret;
-	GError *error = NULL;
-	PkRoleEnum role;
-
-	/* get role -- do we actually need to do anything */
-	pk_client_get_role (application->priv->client_search, &role, NULL, NULL);
-	if (role == PK_ROLE_ENUM_UNKNOWN) {
-		egg_debug ("no defined role, no not requeuing");
-		return FALSE;
-	}
-
-	/* hide details */
-	gpk_application_clear_details (application);
-	gpk_application_clear_packages (application);
-
-	ret = pk_client_requeue (application->priv->client_search, &error);
-	if (!ret) {
-		egg_warning ("failed to requeue the search: %s", error->message);
-		g_error_free (error);
-		return FALSE;
-	}
-	return TRUE;
-}
-
-/**
  * gpk_application_suggest_better_search:
  **/
 static void
@@ -1224,31 +1069,267 @@
 }
 
 /**
+ * gpk_update_viewer_requeue:
+ **/
+static gboolean
+gpk_update_viewer_requeue (GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* retry new action */
+	ret = pk_client_requeue (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("Failed to requeue: %s", error->message);
+		g_error_free (error);
+	}
+	return ret;
+}
+
+/**
+ * gpk_application_finished_get_depends:
+ **/
+static void
+gpk_application_finished_get_depends (GpkApplication *application, PkPackageList *list)
+{
+	GtkWindow *window;
+	gchar *name = NULL;
+	gchar *title = NULL;
+	gchar *message = NULL;
+	gchar **package_ids = NULL;
+	guint length;
+	GtkWidget *dialog;
+
+	/* empty list */
+	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
+	if (pk_package_list_get_size (list) == 0) {
+		gpk_error_dialog_modal (window,
+					/* TRANSLATORS: no packages returned */
+					_("No packages"),
+					/* TRANSLATORS: this package does not depend on any others */
+					_("This package does not depends on any others"), NULL);
+		goto out;
+	}
+
+	length = pk_package_list_get_size (list);
+	package_ids = pk_package_ids_from_id (application->priv->package);
+	name = gpk_dialog_package_id_name_join_locale (package_ids);
+	/* TRANSLATORS: title: show the number of other packages we depend on */
+	title = g_strdup_printf (ngettext ("%i additional package is required for %s",
+					   "%i additional packages are required for %s",
+					   length), length, name);
+
+	/* TRANSLATORS: message: show the list of dependant packages for this package */
+	message = g_strdup_printf (ngettext ("Packages listed below are required for %s to function correctly.",
+					     "Packages listed below are required for %s to function correctly.",
+					     length), name);
+
+	dialog = gtk_message_dialog_new (window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
+	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
+	gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), list);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+out:
+	g_strfreev (package_ids);
+	g_free (name);
+	g_free (title);
+	g_free (message);
+}
+
+/**
+ * gpk_application_finished_get_requires:
+ **/
+static void
+gpk_application_finished_get_requires (GpkApplication *application, PkPackageList *list)
+{
+	GtkWindow *window;
+	gchar *name = NULL;
+	gchar *title = NULL;
+	gchar *message = NULL;
+	gchar **package_ids = NULL;
+	guint length;
+	GtkWidget *dialog;
+
+	/* empty list */
+	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
+	if (pk_package_list_get_size (list) == 0) {
+		gpk_error_dialog_modal (window,
+					/* TRANSLATORS: no packages returned */
+					_("No packages"),
+					/* TRANSLATORS: this package is not required by any others */
+					_("No other packages require this package"), NULL);
+		goto out;
+	}
+
+	length = pk_package_list_get_size (list);
+	package_ids = pk_package_ids_from_id (application->priv->package);
+	name = gpk_dialog_package_id_name_join_locale (package_ids);
+	/* TRANSLATORS: title: how many packages require this package */
+	title = g_strdup_printf (ngettext ("%i package requires %s",
+					   "%i packages require %s",
+					   length), length, name);
+
+	/* TRANSLATORS: show a list of packages for the package */
+	message = g_strdup_printf (ngettext ("Packages listed below require %s to function correctly.",
+					     "Packages listed below require %s to function correctly.",
+					     length), name);
+
+	dialog = gtk_message_dialog_new (window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
+	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
+	gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), list);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+out:
+	g_strfreev (package_ids);
+	g_free (name);
+	g_free (title);
+	g_free (message);
+}
+
+/**
+ * gpk_application_perform_search_idle_cb:
+ **/
+static gboolean
+gpk_application_perform_search_idle_cb (GpkApplication *application)
+{
+	gpk_application_perform_search (application);
+	return FALSE;
+}
+
+/**
+ * gpk_application_primary_requeue:
+ **/
+static gboolean
+gpk_application_primary_requeue (GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* retry new action */
+	ret = pk_client_requeue (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("Failed to requeue: %s", error->message);
+		g_error_free (error);
+	}
+	return ret;
+}
+
+/**
  * gpk_application_finished_cb:
  **/
 static void
-gpk_application_finished_cb (PkClient *client, PkExitEnum exit, guint runtime, GpkApplication *application)
+gpk_application_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkApplication *application)
 {
 	GtkWidget *widget;
 	PkRoleEnum role;
+	PkPackageList *list;
+	gchar **package_ids;
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
 	/* get role */
 	pk_client_get_role (client, &role, NULL, NULL);
+	egg_debug ("role: %s, exit: %s", pk_role_enum_to_text (role), pk_exit_enum_to_text (exit_enum));
+
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "progressbar_progress"));
+	gtk_widget_hide (widget);
+
+	/* reset UI */
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_groups"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "textview_description"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_detail"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_packages"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "entry_text"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "button_apply"));
+	gtk_widget_set_sensitive (widget, TRUE);
+	gpk_application_set_buttons_apply_clear (application);
+
+	/* if secondary, ignore */
+	if (client == application->priv->client_primary &&
+	    (exit_enum == PK_EXIT_ENUM_KEY_REQUIRED ||
+	     exit_enum == PK_EXIT_ENUM_EULA_REQUIRED)) {
+		egg_debug ("ignoring primary sig-required or eula");
+		return;
+	}
+
+	if (role == PK_ROLE_ENUM_GET_CATEGORIES) {
+		/* get complex group list */
+		gpk_application_categories_finished (application);
+	}
+
+	/* get deps */
+	if (role == PK_ROLE_ENUM_GET_DEPENDS &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		list = pk_client_get_package_list (application->priv->client_primary);
+		if (application->priv->dep_check_info_only)
+			gpk_application_finished_get_depends (application, list);
+		else
+			gpk_helper_deps_install_show (application->priv->helper_deps_install, application->priv->package_list, list);
+		g_object_unref (list);
+
+	}
+
+	/* get reqs */
+	if (role == PK_ROLE_ENUM_GET_REQUIRES &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		list = pk_client_get_package_list (application->priv->client_primary);
+		if (application->priv->dep_check_info_only)
+			gpk_application_finished_get_requires (application, list);
+		else
+			gpk_helper_deps_remove_show (application->priv->helper_deps_remove, application->priv->package_list, list);
+		g_object_unref (list);
+	}
+
+	/* we've just agreed to auth or a EULA */
+	if (role == PK_ROLE_ENUM_INSTALL_SIGNATURE ||
+	    role == PK_ROLE_ENUM_ACCEPT_EULA) {
+		if (exit_enum == PK_EXIT_ENUM_SUCCESS)
+			gpk_update_viewer_requeue (application);
+	}
+
+	/* do we need to update the search? */
+	if (role == PK_ROLE_ENUM_INSTALL_PACKAGES ||
+	    role == PK_ROLE_ENUM_REMOVE_PACKAGES) {
+		/* refresh the search as the items may have changed and the filter has not changed */
+		if (exit_enum == PK_EXIT_ENUM_SUCCESS) {
+			/* idle add in the background */
+			g_idle_add ((GSourceFunc) gpk_application_perform_search_idle_cb, application);
+
+			/* this is async */
+			package_ids = pk_package_ids_from_id (application->priv->package);
+			gpk_helper_run_show (application->priv->helper_run, package_ids);
+			g_strfreev (package_ids);
+
+			/* clear if success */
+			g_ptr_array_foreach (application->priv->package_list, (GFunc) g_free, NULL);
+			g_ptr_array_set_size (application->priv->package_list, 0);
+			application->priv->action = PK_ACTION_NONE;
+			gpk_application_set_buttons_apply_clear (application);
+		}
+	}
+
+	/* we've just agreed to auth or a EULA */
+	if (role == PK_ROLE_ENUM_INSTALL_SIGNATURE ||
+	    role == PK_ROLE_ENUM_ACCEPT_EULA) {
+		if (exit_enum == PK_EXIT_ENUM_SUCCESS)
+			gpk_application_primary_requeue (application);
+	}
 
 	if (role == PK_ROLE_ENUM_SEARCH_NAME ||
 	    role == PK_ROLE_ENUM_SEARCH_DETAILS ||
 	    role == PK_ROLE_ENUM_SEARCH_GROUP ||
 	    role == PK_ROLE_ENUM_GET_PACKAGES) {
-
-		/* switch round buttons */
-		gpk_application_set_find_cancel_buttons (application, TRUE);
-
 		/* were there no entries found? */
-		if (exit == PK_EXIT_ENUM_SUCCESS && !application->priv->has_package) {
-
-			/* try to be helpful... */
+		if (exit_enum == PK_EXIT_ENUM_SUCCESS && !application->priv->has_package) {
 			gpk_application_suggest_better_search (application);
 		}
 
@@ -1256,13 +1337,6 @@
 		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "entry_text"));
 		gtk_widget_grab_focus (widget);
 	}
-
-	/* do we need to update the search? */
-	if (role == PK_ROLE_ENUM_INSTALL_PACKAGES ||
-	    role == PK_ROLE_ENUM_REMOVE_PACKAGES) {
-		/* refresh the search as the items may have changed and the filter has not changed */
-		gpk_application_refresh_search_results (application);
-	}
 }
 
 /**
@@ -1275,12 +1349,11 @@
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
-	ret = pk_client_cancel (application->priv->client_search, NULL);
+	ret = pk_client_cancel (application->priv->client_primary, NULL);
 	egg_debug ("canceled? %i", ret);
 
 	/* switch buttons around */
 	if (ret) {
-		gpk_application_set_find_cancel_buttons (application, TRUE);
 		application->priv->search_mode = PK_MODE_UNKNOWN;
 	}
 }
@@ -1321,7 +1394,7 @@
 	egg_debug ("find %s", application->priv->search_text);
 
 	/* reset */
-	ret = pk_client_reset (application->priv->client_search, &error);
+	ret = pk_client_reset (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to reset client: %s", error->message);
 		g_error_free (error);
@@ -1330,15 +1403,15 @@
 
 	/* do the search */
 	if (application->priv->search_type == PK_SEARCH_NAME) {
-		ret = pk_client_search_name (application->priv->client_search,
+		ret = pk_client_search_name (application->priv->client_primary,
 					     application->priv->filters_current,
 					     application->priv->search_text, &error);
 	} else if (application->priv->search_type == PK_SEARCH_DETAILS) {
-		ret = pk_client_search_details (application->priv->client_search,
+		ret = pk_client_search_details (application->priv->client_primary,
 					     application->priv->filters_current,
 					     application->priv->search_text, &error);
 	} else if (application->priv->search_type == PK_SEARCH_FILE) {
-		ret = pk_client_search_file (application->priv->client_search,
+		ret = pk_client_search_file (application->priv->client_primary,
 					     application->priv->filters_current,
 					     application->priv->search_text, &error);
 	} else {
@@ -1374,7 +1447,7 @@
 	g_return_val_if_fail (application->priv->group != NULL, FALSE);
 
 	/* cancel this, we don't care about old results that are pending */
-	ret = pk_client_reset (application->priv->client_search, &error);
+	ret = pk_client_reset (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to reset client: %s", error->message);
 		g_error_free (error);
@@ -1382,11 +1455,11 @@
 	}
 
 	if (application->priv->search_mode == PK_MODE_GROUP) {
-		ret = pk_client_search_group (application->priv->client_search,
+		ret = pk_client_search_group (application->priv->client_primary,
 					      application->priv->filters_current,
 					      application->priv->group, &error);
 	} else {
-		ret = pk_client_get_packages (application->priv->client_search,
+		ret = pk_client_get_packages (application->priv->client_primary,
 					      application->priv->filters_current, &error);
 	}
 
@@ -1425,12 +1498,6 @@
 	} else {
 		egg_debug ("doing nothing");
 	}
-	if (!ret)
-		return ret;
-
-	/* switch around buttons */
-	gpk_application_set_find_cancel_buttons (application, FALSE);
-
 	return ret;
 }
 
@@ -1484,19 +1551,13 @@
 	}
 
 	/* we might have visual stuff running, close them down */
-	ret = pk_client_cancel (application->priv->client_search, &error);
-	if (!ret) {
-		egg_warning ("failed to cancel client: %s", error->message);
-		g_error_free (error);
-		error = NULL;
-	}
-	ret = pk_client_cancel (application->priv->client_details, &error);
+	ret = pk_client_cancel (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to cancel client: %s", error->message);
 		g_error_free (error);
 		error = NULL;
 	}
-	ret = pk_client_cancel (application->priv->client_files, &error);
+	ret = pk_client_cancel (application->priv->client_secondary, &error);
 	if (!ret) {
 		egg_warning ("failed to cancel client: %s", error->message);
 		g_error_free (error);
@@ -1678,44 +1739,50 @@
 	gboolean ret = FALSE;
 	GError *error = NULL;
 	gchar **package_ids = NULL;
-	gchar *exec;
-	GtkWindow *window;
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
 	package_ids = pk_ptr_array_to_strv (application->priv->package_list);
 	if (application->priv->action == PK_ACTION_INSTALL) {
-		gpk_client_set_interaction (application->priv->gclient, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
-		ret = gpk_client_install_package_ids (application->priv->gclient, package_ids, NULL);
-		/* can we show the user the new application? */
-		if (ret) {
-			window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
-			exec = gpk_client_run_show (window, package_ids);
-			if (exec != NULL) {
-				ret = g_spawn_command_line_async (exec, &error);
-				if (!ret) {
-					egg_warning ("failed to run: %s", error->message);
-					g_error_free (error);
-				}
-			}
-			g_free (exec);
+
+		/* reset client */
+		ret = pk_client_reset (application->priv->client_primary, &error);
+		if (!ret) {
+			egg_warning ("failed to cancel: %s", error->message);
+			g_error_free (error);
+			goto out;
+		}
+
+		/* install */
+		application->priv->dep_check_info_only = FALSE;
+		ret = pk_client_get_depends (application->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED), package_ids, TRUE, &error);
+		if (!ret) {
+			egg_warning ("failed to get depends: %s", error->message);
+			g_error_free (error);
+			goto out;
 		}
 	}
 	if (application->priv->action == PK_ACTION_REMOVE) {
-		gpk_client_set_interaction (application->priv->gclient, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
-		ret = gpk_client_remove_package_ids (application->priv->gclient, package_ids, NULL);
-	}
-	g_strfreev (package_ids);
+		/* reset client */
+		ret = pk_client_reset (application->priv->client_primary, &error);
+		if (!ret) {
+			egg_warning ("failed to cancel: %s", error->message);
+			g_error_free (error);
+			goto out;
+		}
 
-	/* refresh the search as the items may have changed and the filter has not changed */
-	if (ret) {
-		/* clear if success */
-		g_ptr_array_foreach (application->priv->package_list, (GFunc) g_free, NULL);
-		g_ptr_array_set_size (application->priv->package_list, 0);
-		application->priv->action = PK_ACTION_NONE;
-		gpk_application_set_buttons_apply_clear (application);
-		gpk_application_refresh_search_results (application);
+		/* install */
+		application->priv->dep_check_info_only = FALSE;
+		ret = pk_client_get_requires (application->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_ids, TRUE, &error);
+		if (!ret) {
+			egg_warning ("failed to get requires: %s", error->message);
+			g_error_free (error);
+			goto out;
+		}
 	}
+out:
+	g_strfreev (package_ids);
+	return;
 }
 
 static void
@@ -1912,7 +1979,7 @@
 	gtk_widget_set_sensitive (widget, ret);
 
 	/* cancel any previous request */
-	ret = pk_client_reset (application->priv->client_details, &error);
+	ret = pk_client_reset (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to cancel, and adding to queue: %s", error->message);
 		g_error_free (error);
@@ -1921,7 +1988,7 @@
 
 	/* get the details */
 	package_ids = pk_package_ids_from_id (application->priv->package);
-	ret = pk_client_get_details (application->priv->client_details, package_ids, &error);
+	ret = pk_client_get_details (application->priv->client_primary, package_ids, &error);
 	g_strfreev (package_ids);
 	if (!ret) {
 		egg_warning ("failed to get details: %s", error->message);
@@ -2271,8 +2338,28 @@
 static void
 gpk_application_menu_refresh_cb (GtkAction *action, GpkApplication *application)
 {
-	gpk_client_set_interaction (application->priv->gclient, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
-	gpk_client_refresh_cache (application->priv->gclient, NULL);
+	gboolean ret;
+	GError *error = NULL;
+
+	g_return_if_fail (PK_IS_APPLICATION (application));
+
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* set correct view */
+	ret = pk_client_refresh_cache (application->priv->client_primary, TRUE, &error);
+	if (!ret) {
+		egg_warning ("cannot get refresh cache: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
 }
 
 /**
@@ -2536,6 +2623,26 @@
 
 	g_return_if_fail (PK_IS_APPLICATION (application));
 
+	if (application->priv->action == PK_ACTION_INSTALL ||
+	    application->priv->action == PK_ACTION_REMOVE) {
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_groups"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "textview_description"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_detail"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "treeview_packages"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "entry_text"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "button_apply"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "button_clear"));
+		gtk_widget_set_sensitive (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "button_find"));
+		gtk_widget_set_sensitive (widget, FALSE);
+	}
+
 	widget = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "hbox_status"));
 	if (status == PK_STATUS_ENUM_FINISHED) {
 		gtk_widget_hide (widget);
@@ -2568,6 +2675,188 @@
 	gtk_widget_set_sensitive (widget, allow_cancel);
 }
 
+
+/**
+ * gpk_application_repo_signature_event_cb:
+ **/
+static void
+gpk_application_repo_signature_event_cb (GpkHelperRepoSignature *helper_repo_signature, GtkResponseType type, const gchar *key_id, const gchar *package_id, GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* install signature */
+	ret = pk_client_install_signature (application->priv->client_secondary, PK_SIGTYPE_ENUM_GPG, key_id, package_id, &error);
+	if (!ret) {
+		egg_warning ("cannot install signature: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_application_eula_event_cb:
+ **/
+static void
+gpk_application_eula_event_cb (GpkHelperEula *helper_eula, GtkResponseType type, const gchar *eula_id, GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* install signature */
+	ret = pk_client_accept_eula (application->priv->client_secondary, eula_id, &error);
+	if (!ret) {
+		egg_warning ("cannot accept eula: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_application_deps_remove_event_cb:
+ **/
+static void
+gpk_application_deps_remove_event_cb (GpkHelperDepsRemove *helper_deps_remove, GtkResponseType type, GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+	gchar **package_ids = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* actually remove packages this time */
+	package_ids = pk_ptr_array_to_strv (application->priv->package_list);
+	ret = pk_client_remove_packages (application->priv->client_primary, package_ids, TRUE, FALSE, &error);
+	if (!ret) {
+		egg_warning ("cannot remove packages: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
+}
+
+/**
+ * gpk_application_deps_install_event_cb:
+ **/
+static void
+gpk_application_deps_install_event_cb (GpkHelperDepsInstall *helper_deps_install, GtkResponseType type, GpkApplication *application)
+{
+	gboolean ret;
+	GError *error = NULL;
+	gchar **package_ids = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* actually remove packages this time */
+	package_ids = pk_ptr_array_to_strv (application->priv->package_list);
+	ret = pk_client_install_packages (application->priv->client_primary, package_ids, &error);
+	if (!ret) {
+		egg_warning ("cannot install packages: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
+}
+
+/**
+ * gpk_application_media_change_event_cb:
+ **/
+static void
+gpk_application_media_change_event_cb (GpkHelperMediaChange *helper_media_change, GtkResponseType type, GpkApplication *application)
+{
+	if (type != GTK_RESPONSE_YES)
+		goto out;
+
+	/* requeue */
+	gpk_update_viewer_requeue (application);
+out:
+	return;
+}
+
+/**
+ * gpk_application_eula_required_cb:
+ **/
+static void
+gpk_application_eula_required_cb (PkClient *client, const gchar *eula_id, const gchar *package_id,
+				    const gchar *vendor_name, const gchar *license_agreement, GpkApplication *application)
+{
+	/* use the helper */
+	gpk_helper_eula_show (application->priv->helper_eula, eula_id, package_id, vendor_name, license_agreement);
+}
+
+/**
+ * gpk_application_media_change_required_cb:
+ **/
+static void
+gpk_application_media_change_required_cb (PkClient *client, PkMediaTypeEnum type, const gchar *media_id, const gchar *media_text, GpkApplication *application)
+{
+	/* use the helper */
+	gpk_helper_media_change_show (application->priv->helper_media_change, type, media_id, media_text);
+}
+
+/**
+ * gpk_application_repo_signature_required_cb:
+ **/
+static void
+gpk_application_repo_signature_required_cb (PkClient *client, const gchar *package_id, const gchar *repository_name,
+					      const gchar *key_url, const gchar *key_userid, const gchar *key_id,
+					      const gchar *key_fingerprint, const gchar *key_timestamp,
+					      PkSigTypeEnum type, GpkApplication *application)
+{
+	/* use the helper */
+	gpk_helper_repo_signature_show (application->priv->helper_repo_signature, package_id, repository_name, key_url, key_userid, key_id, key_fingerprint, key_timestamp);
+}
+
 /**
  * gpk_application_package_row_activated_cb:
  **/
@@ -2768,10 +3057,10 @@
 }
 
 /**
- * gpk_application_categories_finished_cb:
+ * gpk_application_categories_finished:
  **/
 static void
-gpk_application_categories_finished_cb (PkClient *client, PkExitEnum exit, guint runtime, GpkApplication *application)
+gpk_application_categories_finished (GpkApplication *application)
 {
 	PkObjList *list;
 	const PkCategoryObj *obj;
@@ -2819,7 +3108,7 @@
 	}
 
 	/* get return values */
-	list = pk_client_get_cached_objects (client);
+	list = pk_client_get_cached_objects (application->priv->client_primary);
 	if (list->len == 0) {
 		egg_warning ("no results from GetCategories");
 		goto out;
@@ -2859,7 +3148,7 @@
 	gtk_tree_view_collapse_all (treeview);
 	g_object_unref (list);
 out:
-	g_object_unref (client);
+	return;
 }
 
 /**
@@ -2869,34 +3158,30 @@
 gpk_application_create_group_list_categories (GpkApplication *application)
 {
 	GError *error = NULL;
-	PkClient *client;
-	gboolean ret;
+	gboolean ret = FALSE;
 
 	/* check we can do this */
 	if (!pk_bitfield_contain (application->priv->roles, PK_ROLE_ENUM_GET_CATEGORIES)) {
 		egg_warning ("backend does not support complex groups");
-		return FALSE;
+		goto out;
 	}
 
-	/* async */
-	client = pk_client_new ();
-	pk_client_set_use_buffer (client, TRUE, NULL);
-	g_signal_connect (client, "finished",
-			  G_CALLBACK (gpk_application_categories_finished_cb), application);
-	g_signal_connect (client, "finished",
-			  G_CALLBACK (gpk_application_finished_cb), application);
-	g_signal_connect (client, "status-changed",
-			  G_CALLBACK (gpk_application_status_changed_cb), application);
+	/* reset client */
+	ret = pk_client_reset (application->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
 
 	/* get categories supported */
-	ret = pk_client_get_categories (client, &error);
+	ret = pk_client_get_categories (application->priv->client_primary, &error);
 	if (!ret) {
 		egg_warning ("failed to get categories: %s", error->message);
 		g_error_free (error);
-		g_object_unref (client);
+		goto out;
 	}
-
-	/* client will be unreff'd in finished handler */
+out:
 	return ret;
 }
 
@@ -2938,6 +3223,52 @@
 }
 
 /**
+ * gpk_application_files_cb:
+ **/
+static void
+gpk_application_files_cb (PkClient *client, const gchar *package_id,
+			  const gchar *filelist, GpkApplication *application)
+{
+	GPtrArray *array;
+	gchar **files;
+	gchar *title;
+	GtkWindow *window;
+	GtkWidget *dialog;
+	PkPackageId *id;
+
+	g_return_if_fail (PK_IS_APPLICATION (application));
+
+	files = g_strsplit (filelist, ";", -1);
+
+	/* convert to pointer array */
+	array = pk_strv_to_ptr_array (files);
+	g_ptr_array_sort (array, (GCompareFunc) gpk_application_strcmp_indirect);
+
+	/* title */
+	id = pk_package_id_new_from_string (application->priv->package);
+	/* TRANSLATORS: title: how many files are installed by the application */
+	title = g_strdup_printf (ngettext ("%i file installed by %s",
+					   "%i files installed by %s",
+					   array->len), array->len, id->name);
+
+	window = GTK_WINDOW (gtk_builder_get_object (application->priv->builder, "window_manager"));
+	dialog = gtk_message_dialog_new (window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", title);
+	gpk_dialog_embed_file_list_widget (GTK_DIALOG (dialog), array);
+	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 250);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+
+	g_free (title);
+	g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+	g_ptr_array_free (array, TRUE);
+	g_strfreev (files);
+	pk_package_id_free (id);
+}
+
+/**
  * gpk_application_init:
  **/
 static void
@@ -2962,6 +3293,7 @@
 	application->priv->url = NULL;
 	application->priv->search_text = NULL;
 	application->priv->has_package = FALSE;
+	application->priv->dep_check_info_only = FALSE;
 	application->priv->details_event_id = 0;
 	application->priv->package_list = g_ptr_array_new ();
 
@@ -3008,56 +3340,40 @@
 					   "/usr/share/PackageKit/icons");
 
 	application->priv->control = pk_control_new ();
-	application->priv->gclient = gpk_client_new ();
-
-	application->priv->client_search = pk_client_new ();
-	g_signal_connect (application->priv->client_search, "package",
-			  G_CALLBACK (gpk_application_package_cb), application);
-	g_signal_connect (application->priv->client_search, "error-code",
-			  G_CALLBACK (gpk_application_error_code_cb), application);
-	g_signal_connect (application->priv->client_search, "finished",
-			  G_CALLBACK (gpk_application_finished_cb), application);
-	g_signal_connect (application->priv->client_search, "status-changed",
-			  G_CALLBACK (gpk_application_status_changed_cb), application);
-	g_signal_connect (application->priv->client_search, "allow-cancel",
-			  G_CALLBACK (gpk_application_allow_cancel_cb), application);
 
-	application->priv->client_action = pk_client_new ();
-	g_signal_connect (application->priv->client_action, "package",
+	/* this is what we use mainly */
+	application->priv->client_primary = pk_client_new ();
+	pk_client_set_use_buffer (application->priv->client_primary, TRUE, NULL);
+	g_signal_connect (application->priv->client_primary, "files",
+			  G_CALLBACK (gpk_application_files_cb), application);
+	g_signal_connect (application->priv->client_primary, "package",
 			  G_CALLBACK (gpk_application_package_cb), application);
-	g_signal_connect (application->priv->client_action, "error-code",
-			  G_CALLBACK (gpk_application_error_code_cb), application);
-	g_signal_connect (application->priv->client_action, "finished",
-			  G_CALLBACK (gpk_application_finished_cb), application);
-	g_signal_connect (application->priv->client_action, "status-changed",
-			  G_CALLBACK (gpk_application_status_changed_cb), application);
-	g_signal_connect (application->priv->client_action, "allow-cancel",
-			  G_CALLBACK (gpk_application_allow_cancel_cb), application);
-	g_signal_connect (application->priv->client_action, "repo-detail",
-			  G_CALLBACK (pk_application_repo_detail_cb), application);
-
-	application->priv->client_details = pk_client_new ();
-	g_signal_connect (application->priv->client_details, "details",
+	g_signal_connect (application->priv->client_primary, "details",
 			  G_CALLBACK (gpk_application_details_cb), application);
-	g_signal_connect (application->priv->client_details, "error-code",
+	g_signal_connect (application->priv->client_primary, "error-code",
 			  G_CALLBACK (gpk_application_error_code_cb), application);
-	g_signal_connect (application->priv->client_details, "finished",
+	g_signal_connect (application->priv->client_primary, "finished",
 			  G_CALLBACK (gpk_application_finished_cb), application);
-	g_signal_connect (application->priv->client_details, "status-changed",
+	g_signal_connect (application->priv->client_primary, "status-changed",
 			  G_CALLBACK (gpk_application_status_changed_cb), application);
-	g_signal_connect (application->priv->client_details, "allow-cancel",
+	g_signal_connect (application->priv->client_primary, "allow-cancel",
 			  G_CALLBACK (gpk_application_allow_cancel_cb), application);
-
-	application->priv->client_files = pk_client_new ();
-	pk_client_set_use_buffer (application->priv->client_files, TRUE, NULL);
-	g_signal_connect (application->priv->client_files, "error-code",
+	g_signal_connect (application->priv->client_primary, "repo-detail",
+			  G_CALLBACK (pk_application_repo_detail_cb), application);
+	g_signal_connect (application->priv->client_primary, "repo-signature-required",
+			  G_CALLBACK (gpk_application_repo_signature_required_cb), application);
+	g_signal_connect (application->priv->client_primary, "eula-required",
+			  G_CALLBACK (gpk_application_eula_required_cb), application);
+	g_signal_connect (application->priv->client_primary, "media-change-required",
+			  G_CALLBACK (gpk_application_media_change_required_cb), application);
+
+	/* this is for auth and eula callbacks */
+	application->priv->client_secondary = pk_client_new ();
+	pk_client_set_use_buffer (application->priv->client_secondary, TRUE, NULL);
+	g_signal_connect (application->priv->client_secondary, "error-code",
 			  G_CALLBACK (gpk_application_error_code_cb), application);
-	g_signal_connect (application->priv->client_files, "finished",
+	g_signal_connect (application->priv->client_secondary, "finished",
 			  G_CALLBACK (gpk_application_finished_cb), application);
-	g_signal_connect (application->priv->client_files, "status-changed",
-			  G_CALLBACK (gpk_application_status_changed_cb), application);
-	g_signal_connect (application->priv->client_files, "allow-cancel",
-			  G_CALLBACK (gpk_application_allow_cancel_cb), application);
 
 	/* get bitfield */
 	application->priv->roles = pk_control_get_actions (application->priv->control, NULL);
@@ -3092,9 +3408,29 @@
 
 	main_window = GTK_WIDGET (gtk_builder_get_object (application->priv->builder, "window_manager"));
 
-	/* make GpkClient windows modal */
-	gtk_widget_realize (main_window);
-	gpk_client_set_parent (application->priv->gclient, GTK_WINDOW (main_window));
+	/* helpers */
+	application->priv->helper_repo_signature = gpk_helper_repo_signature_new ();
+	g_signal_connect (application->priv->helper_repo_signature, "event", G_CALLBACK (gpk_application_repo_signature_event_cb), application);
+	gpk_helper_repo_signature_set_parent (application->priv->helper_repo_signature, GTK_WINDOW (main_window));
+
+	application->priv->helper_eula = gpk_helper_eula_new ();
+	g_signal_connect (application->priv->helper_eula, "event", G_CALLBACK (gpk_application_eula_event_cb), application);
+	gpk_helper_eula_set_parent (application->priv->helper_eula, GTK_WINDOW (main_window));
+
+	application->priv->helper_run = gpk_helper_run_new ();
+	gpk_helper_run_set_parent (application->priv->helper_run, GTK_WINDOW (main_window));
+
+	application->priv->helper_deps_remove = gpk_helper_deps_remove_new ();
+	g_signal_connect (application->priv->helper_deps_remove, "event", G_CALLBACK (gpk_application_deps_remove_event_cb), application);
+	gpk_helper_deps_remove_set_parent (application->priv->helper_deps_remove, GTK_WINDOW (main_window));
+
+	application->priv->helper_deps_install = gpk_helper_deps_install_new ();
+	g_signal_connect (application->priv->helper_deps_install, "event", G_CALLBACK (gpk_application_deps_install_event_cb), application);
+	gpk_helper_deps_install_set_parent (application->priv->helper_deps_install, GTK_WINDOW (main_window));
+
+	application->priv->helper_media_change = gpk_helper_media_change_new ();
+	g_signal_connect (application->priv->helper_media_change, "event", G_CALLBACK (gpk_application_media_change_event_cb), application);
+	gpk_helper_media_change_set_parent (application->priv->helper_media_change, GTK_WINDOW (main_window));
 
 	/* Hide window first so that the dialogue resizes itself without redrawing */
 	gtk_widget_hide (main_window);
@@ -3335,6 +3671,8 @@
 
 	g_signal_connect (widget, "activate",
 			  G_CALLBACK (gpk_application_find_cb), application);
+	g_signal_connect (widget, "paste-clipboard",
+			  G_CALLBACK (gpk_application_find_cb), application);
 	g_signal_connect (widget, "icon-press",
 			  G_CALLBACK (gpk_application_entry_text_icon_press_cb), application);
 
@@ -3465,7 +3803,7 @@
 		gpk_application_create_group_list_enum (application);
 
 	/* get repos, so we can show the full name in the software source box */
-	ret = pk_client_get_repo_list (application->priv->client_action, PK_FILTER_ENUM_NONE, &error);
+	ret = pk_client_get_repo_list (application->priv->client_primary, PK_FILTER_ENUM_NONE, &error);
 	if (!ret) {
 		egg_warning ("failed to get repo list: %s", error->message);
 		g_error_free (error);
@@ -3540,16 +3878,19 @@
 	g_object_unref (application->priv->packages_store);
 	g_object_unref (application->priv->details_store);
 	g_object_unref (application->priv->control);
-	g_object_unref (application->priv->client_search);
-	g_object_unref (application->priv->client_action);
-	g_object_unref (application->priv->client_details);
-	g_object_unref (application->priv->client_files);
+	g_object_unref (application->priv->client_primary);
+	g_object_unref (application->priv->client_secondary);
 	g_object_unref (application->priv->pconnection);
 	g_object_unref (application->priv->desktop);
 	g_object_unref (application->priv->gconf_client);
-	g_object_unref (application->priv->gclient);
 	g_object_unref (application->priv->markdown);
 	g_object_unref (application->priv->builder);
+	g_object_unref (application->priv->helper_eula);
+	g_object_unref (application->priv->helper_run);
+	g_object_unref (application->priv->helper_deps_remove);
+	g_object_unref (application->priv->helper_deps_install);
+	g_object_unref (application->priv->helper_media_change);
+	g_object_unref (application->priv->helper_repo_signature);
 
 	g_ptr_array_foreach (application->priv->package_list, (GFunc) g_free, NULL);
 	g_ptr_array_set_size (application->priv->package_list, 0);

Modified: trunk/src/gpk-auto-refresh.c
==============================================================================
--- trunk/src/gpk-auto-refresh.c	(original)
+++ trunk/src/gpk-auto-refresh.c	Tue Apr 14 16:28:59 2009
@@ -364,6 +364,17 @@
 }
 
 /**
+ * gpk_auto_refresh_maybe_get_updates_logon_cb:
+ **/
+static gboolean
+gpk_auto_refresh_maybe_get_updates_logon_cb (GpkAutoRefresh *arefresh)
+{
+	gpk_auto_refresh_maybe_get_updates (arefresh);
+	/* never repeat, even if failure */
+	return FALSE;
+}
+
+/**
  * gpk_auto_refresh_change_state:
  **/
 static gboolean
@@ -389,7 +400,7 @@
 			 * we need to wait until upper layers  finish hooking up to the signal first. */
 			if (arefresh->priv->force_get_updates_login_timeout_id == 0)
 				arefresh->priv->force_get_updates_login_timeout_id =
-					g_timeout_add_seconds (GPK_UPDATES_LOGIN_TIMEOUT, (GSourceFunc) gpk_auto_refresh_maybe_get_updates, arefresh);
+					g_timeout_add_seconds (GPK_UPDATES_LOGIN_TIMEOUT, (GSourceFunc) gpk_auto_refresh_maybe_get_updates_logon_cb, arefresh);
 		}
 	}
 

Modified: trunk/src/gpk-cell-renderer-info.c
==============================================================================
--- trunk/src/gpk-cell-renderer-info.c	(original)
+++ trunk/src/gpk-cell-renderer-info.c	Tue Apr 14 16:28:59 2009
@@ -33,7 +33,8 @@
 
 enum {
 	PROP_0,
-	PROP_VALUE
+	PROP_VALUE,
+	PROP_IGNORE_VALUES
 };
 
 #define GPK_CELL_RENDERER_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GPK_TYPE_CELL_RENDERER_INFO, GpkCellRendererInfoPrivate))
@@ -42,6 +43,7 @@
 {
 	PkInfoEnum		 value;
 	const gchar		*icon_name;
+	GPtrArray		*ignore;
 };
 
 G_DEFINE_TYPE (GpkCellRendererInfo, gpk_cell_renderer_info, GTK_TYPE_CELL_RENDERER_PIXBUF)
@@ -64,23 +66,58 @@
 	}
 }
 
+static gboolean
+gpk_cell_renderer_should_show (GpkCellRendererInfo *cru)
+{
+	guint i;
+	gboolean ret = FALSE;
+	GPtrArray *array;
+	PkInfoEnum info;
+
+	/* are we in the ignore array */
+	array = cru->priv->ignore;
+	for (i=0; i<array->len; i++) {
+		info = GPOINTER_TO_UINT (g_ptr_array_index (array, i));
+		if (info == cru->priv->value)
+			goto out;
+	}
+	ret = TRUE;
+out:
+	return ret;
+}
+
 static void
 gpk_cell_renderer_info_set_property (GObject *object, guint param_id,
 				     const GValue *value, GParamSpec *pspec)
 {
+	const gchar *text;
+	gchar **split;
+	gboolean ret;
+	guint i;
+	PkInfoEnum info;
 	GpkCellRendererInfo *cru = GPK_CELL_RENDERER_INFO (object);
 
 	switch (param_id) {
 	case PROP_VALUE:
 		cru->priv->value = g_value_get_uint (value);
-		if (cru->priv->value == PK_INFO_ENUM_UNKNOWN) {
-			g_object_set (cru, "visible", FALSE, NULL);
+		ret = gpk_cell_renderer_should_show (cru);
+		if (!ret) {
+			g_object_set (cru, "icon-name", "", NULL);
 		} else {
 			cru->priv->icon_name = gpk_info_status_enum_to_icon_name (cru->priv->value);
-			g_object_set (cru, "visible", TRUE, NULL);
 			g_object_set (cru, "icon-name", cru->priv->icon_name, NULL);
 		}
 		break;
+	case PROP_IGNORE_VALUES:
+		/* split up ignore values */
+		text = g_value_get_string (value);
+		split = g_strsplit (text, ",", -1);
+		for (i=0; split[i] != NULL; i++) {
+			info = pk_info_enum_from_text (split[i]);
+			g_ptr_array_add (cru->priv->ignore, GUINT_TO_POINTER (info));
+		}
+		g_strfreev (split);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 		break;
@@ -96,6 +133,7 @@
 {
 	GpkCellRendererInfo *cru;
 	cru = GPK_CELL_RENDERER_INFO (object);
+	g_ptr_array_free (cru->priv->ignore, TRUE);
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -116,6 +154,9 @@
 	g_object_class_install_property (object_class, PROP_VALUE,
 					 g_param_spec_uint ("value", "VALUE",
 					 "VALUE", 0, G_MAXUINT, PK_INFO_ENUM_UNKNOWN, G_PARAM_READWRITE));
+	g_object_class_install_property (object_class, PROP_IGNORE_VALUES,
+					 g_param_spec_string ("ignore-values", "IGNORE-VALUES",
+					 "IGNORE-VALUES", "unknown", G_PARAM_WRITABLE));
 
 	g_type_class_add_private (object_class, sizeof (GpkCellRendererInfoPrivate));
 }
@@ -129,6 +170,7 @@
 	cru->priv = GPK_CELL_RENDERER_INFO_GET_PRIVATE (cru);
 	cru->priv->value = PK_INFO_ENUM_UNKNOWN;
 	cru->priv->icon_name = NULL;
+	cru->priv->ignore = g_ptr_array_new ();
 }
 
 /**

Modified: trunk/src/gpk-check-update.c
==============================================================================
--- trunk/src/gpk-check-update.c	(original)
+++ trunk/src/gpk-check-update.c	Tue Apr 14 16:28:59 2009
@@ -43,13 +43,15 @@
 #include "egg-string.h"
 #include "egg-dbus-monitor.h"
 
+#include "gpk-consolekit.h"
 #include "gpk-common.h"
 #include "gpk-gnome.h"
 #include "gpk-smart-icon.h"
 #include "gpk-auto-refresh.h"
-#include "gpk-client.h"
 #include "gpk-check-update.h"
 #include "gpk-enum.h"
+#include "gpk-error.h"
+#include "gpk-helper-repo-signature.h"
 
 static void     gpk_check_update_finalize	(GObject	     *object);
 
@@ -57,8 +59,6 @@
 
 /* the maximum number of lines of data on the libnotify widget */
 #define GPK_CHECK_UPDATE_MAX_NUMBER_SECURITY_ENTRIES	7
-#define ACTION_DISTRO_UPGRADE_INFO 			"distro-upgrade-info"
-#define ACTION_DISTRO_UPGRADE_DO_NOT_SHOW		"distro-upgrade-do-not-show-available"
 
 struct GpkCheckUpdatePrivate
 {
@@ -66,15 +66,11 @@
 	PkConnection		*pconnection;
 	PkTaskList		*tlist;
 	PkControl		*control;
+	GpkHelperRepoSignature	*helper_repo_signature;
 	GpkAutoRefresh		*arefresh;
-	GpkClient		*gclient_refresh_cache;
-	GpkClient		*gclient_update_system;
-	GpkClient		*gclient_get_updates;
-	GpkClient		*gclient_get_distro_upgrades;
+	PkClient		*client_primary;
+	PkClient		*client_secondary;
 	GConfClient		*gconf_client;
-	gboolean		 cache_okay;
-	gboolean		 cache_update_in_progress;
-	gboolean		 get_updates_in_progress;
 	guint			 number_updates_critical_last_shown;
 	NotifyNotification	*notification_updates_available;
 	GPtrArray		*important_updates_array;
@@ -290,7 +286,7 @@
 	g_return_val_if_fail (GPK_IS_CHECK_UPDATE (cupdate), FALSE);
 
 	/* debug so we can catch polling */
-	egg_debug ("polling check");
+	egg_debug ("post updates check");
 
 	gpk_check_update_query_updates (cupdate, FALSE);
 	return FALSE;
@@ -303,18 +299,25 @@
 gpk_check_update_update_system (GpkCheckUpdate *cupdate)
 {
 	gboolean ret;
-	ret = gpk_client_update_system (cupdate->priv->gclient_update_system, NULL);
+	GError *error = NULL;
 
-	/* this isn't valid anymore */
-	if (ret)
-		cupdate->priv->number_updates_critical_last_shown = 0;
+	ret = pk_client_reset (cupdate->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
 
-	/* we failed, show the icon */
+	ret = pk_client_update_system (cupdate->priv->client_primary, &error);
 	if (!ret) {
+		/* we failed, show the icon */
+		egg_warning ("cannot update system: %s", error->message);
+		g_error_free (error);
 		gpk_smart_icon_set_icon_name (cupdate->priv->sicon, NULL);
 		/* we failed, so re-get the update list */
 		g_timeout_add_seconds (2, (GSourceFunc) gpk_check_update_get_updates_post_update_cb, cupdate);
 	}
+out:
 	return ret;
 }
 
@@ -326,7 +329,6 @@
 {
 	GpkCheckUpdate *cupdate = GPK_CHECK_UPDATE (data);
 	g_return_if_fail (GPK_IS_CHECK_UPDATE (cupdate));
-	gpk_client_set_interaction (cupdate->priv->gclient_update_system, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
 	gpk_check_update_update_system (cupdate);
 }
 
@@ -400,41 +402,64 @@
 	gchar **package_ids;
 	GpkCheckUpdate *cupdate = GPK_CHECK_UPDATE (data);
 
-	if (egg_strequal (action, "update-all-packages")) {
-		gpk_client_set_interaction (cupdate->priv->gclient_update_system, GPK_CLIENT_INTERACT_WARNING);
+	if (egg_strequal (action, "do-not-show-complete-restart")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_UPDATE_COMPLETE_RESTART);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_COMPLETE_RESTART, FALSE, NULL);
+	} else if (egg_strequal (action, "do-not-show-complete")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_UPDATE_COMPLETE);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_COMPLETE, FALSE, NULL);
+	} else if (egg_strequal (action, "do-not-show-update-started")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_UPDATE_STARTED);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_STARTED, FALSE, NULL);
+	} else if (egg_strequal (action, "do-not-show-notify-critical")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_CRITICAL);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_CRITICAL, FALSE, NULL);
+	} else if (egg_strequal (action, "do-not-show-update-not-battery")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_UPDATE_NOT_BATTERY);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_NOT_BATTERY, FALSE, NULL);
+	} else if (egg_strequal (action, "distro-upgrade-do-not-show-available")) {
+		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_DISTRO_UPGRADES);
+		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_DISTRO_UPGRADES, FALSE, NULL);
+//	} else if (egg_strequal (action, "show-error-details")) {
+//		/* TRANSLATORS: detailed text about the error */
+//		gpk_error_dialog (_("Error details"), _("Package Manager error details"), cupdate->priv->error_details);
+	} else if (egg_strequal (action, "cancel")) {
+		/* try to cancel */
+		ret = pk_client_cancel (cupdate->priv->client_primary, &error);
+		if (!ret) {
+			egg_warning ("failed to cancel client: %s", error->message);
+			g_error_free (error);
+		}
+	} else if (egg_strequal (action, "update-all-packages")) {
 		gpk_check_update_update_system (cupdate);
 	} else if (egg_strequal (action, "update-just-security")) {
 
+		ret = pk_client_reset (cupdate->priv->client_primary, &error);
+		if (!ret) {
+			egg_warning ("cannot reset client: %s", error->message);
+			g_error_free (error);
+			goto out;
+		}
+
 		/* just update the important updates */
 		package_ids = pk_package_ids_from_array (cupdate->priv->important_updates_array);
-		gpk_client_set_interaction (cupdate->priv->gclient_update_system, GPK_CLIENT_INTERACT_WARNING);
-		ret = gpk_client_update_packages (cupdate->priv->gclient_update_system, package_ids, &error);
+		ret = pk_client_update_packages (cupdate->priv->client_primary, package_ids, &error);
 		if (!ret) {
 			egg_warning ("Individual updates failed: %s", error->message);
 			g_error_free (error);
 		}
-		/* this isn't valid anymore */
-		if (ret)
-			cupdate->priv->number_updates_critical_last_shown = 0;
 		g_strfreev (package_ids);
 
-	} else if (egg_strequal (action, "do-not-show-notify-critical")) {
-		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_CRITICAL);
-		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_CRITICAL, FALSE, NULL);
-	} else if (egg_strequal (action, "do-not-show-update-not-battery")) {
-		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_UPDATE_NOT_BATTERY);
-		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_NOT_BATTERY, FALSE, NULL);
-	} else if (egg_strequal (action, ACTION_DISTRO_UPGRADE_INFO)) {
+	} else if (egg_strequal (action, "distro-upgrade-info")) {
 		ret = g_spawn_command_line_async ("/usr/share/PackageKit/pk-upgrade-distro.sh", NULL);
 		if (!ret) {
 			egg_warning ("Failure launching pk-upgrade-distro.sh");
 		}
-	} else if (egg_strequal (action, ACTION_DISTRO_UPGRADE_DO_NOT_SHOW)) {
-		egg_debug ("set %s to FALSE", GPK_CONF_NOTIFY_DISTRO_UPGRADES);
-		gconf_client_set_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_DISTRO_UPGRADES, FALSE, NULL);
 	} else {
 		egg_warning ("unknown action id: %s", action);
 	}
+out:
+	return;
 }
 
 /**
@@ -672,6 +697,93 @@
 static gboolean
 gpk_check_update_query_updates (GpkCheckUpdate *cupdate, gboolean policy_action)
 {
+	gboolean ret = FALSE;
+	GError *error = NULL;
+
+	g_return_val_if_fail (GPK_IS_CHECK_UPDATE (cupdate), FALSE);
+
+	/* No point if we are already updating */
+	if (pk_task_list_contains_role (cupdate->priv->tlist, PK_ROLE_ENUM_UPDATE_PACKAGES) ||
+	    pk_task_list_contains_role (cupdate->priv->tlist, PK_ROLE_ENUM_UPDATE_SYSTEM)) {
+		egg_debug ("Not checking for updates as already in progress");
+		goto out;
+	}
+
+	ret = pk_client_reset (cupdate->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	ret = pk_client_get_updates (cupdate->priv->client_primary, PK_FILTER_ENUM_NONE, &error);
+	if (!ret) {
+		egg_warning ("cannot get updates: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return ret;
+}
+
+/**
+ * gpk_check_update_notify_doing_updates:
+ **/
+static void
+gpk_check_update_notify_doing_updates (GpkCheckUpdate *cupdate)
+{
+	gboolean ret;
+	GError *error = NULL;
+	NotifyNotification *notification;
+
+	/* in GConf? */
+	ret = gconf_client_get_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_CRITICAL, NULL);
+	if (!ret)
+		goto out;
+
+	/* TRANSLATORS: title: notification when we scheduled an automatic update */
+	notification = notify_notification_new (_("Updates are being installed"),
+						/* TRANSLATORS: tell the user why the hard disk is grinding... */
+						_("Updates are being automatically installed on your computer"),
+						"software-update-urgent", NULL);
+	notify_notification_set_timeout (notification, 15000);
+	notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+	/* TRANSLATORS: button: cancel the update system */
+	notify_notification_add_action (notification, "cancel",
+					_("Cancel update"), gpk_check_update_libnotify_cb, cupdate, NULL);
+	/* TRANSLATORS: button: don't show this again */
+	notify_notification_add_action (notification, "do-not-show-update-started",
+					_("Do not show this again"), gpk_check_update_libnotify_cb, cupdate, NULL);
+	ret = notify_notification_show (notification, &error);
+	if (!ret) {
+		egg_warning ("error: %s", error->message);
+		g_error_free (error);
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_check_update_policy_all_idle_cb:
+ **/
+static gboolean
+gpk_check_update_policy_all_idle_cb (GpkCheckUpdate *cupdate)
+{
+	gboolean ret;
+	ret = gpk_check_update_update_system (cupdate);
+	if (ret)
+		gpk_check_update_notify_doing_updates (cupdate);
+
+	/* never repeat */
+	return FALSE;
+}
+
+/**
+ * gpk_check_update_process_updates:
+ **/
+static gboolean
+gpk_check_update_process_updates (GpkCheckUpdate *cupdate, PkPackageList *list, gboolean policy_action)
+{
 	const PkPackageObj *obj;
 	guint length;
 	guint i;
@@ -685,35 +797,10 @@
 	const gchar *icon;
 	gchar *package_id;
 	gchar **package_ids;
-	PkPackageList *list;
 	GError *error = NULL;
 
 	g_return_val_if_fail (GPK_IS_CHECK_UPDATE (cupdate), FALSE);
 
-	/* are we already called */
-	if (cupdate->priv->get_updates_in_progress) {
-		egg_debug ("GetUpdate already in progress");
-		return FALSE;
-	}
-
-	/* No point if we are already updating */
-	if (pk_task_list_contains_role (cupdate->priv->tlist, PK_ROLE_ENUM_UPDATE_PACKAGES) ||
-	    pk_task_list_contains_role (cupdate->priv->tlist, PK_ROLE_ENUM_UPDATE_SYSTEM)) {
-		egg_debug ("Not checking for updates as already in progress");
-		return FALSE;
-	}
-
-	/* get updates */
-	gpk_client_set_interaction (cupdate->priv->gclient_get_updates, GPK_CLIENT_INTERACT_NEVER);
-	cupdate->priv->get_updates_in_progress = TRUE;
-	list = gpk_client_get_updates (cupdate->priv->gclient_get_updates, &error);
-	cupdate->priv->get_updates_in_progress = FALSE;
-	if (list == NULL) {
-		egg_warning ("failed to get updates: %s", error->message);
-		g_error_free (error);
-		return FALSE;
-	}
-
 	/* sort by name */
 	pk_package_list_sort (list);
 
@@ -776,11 +863,8 @@
 	/* TRANSLATORS: tooltip: how many updates are waiting to be applied */
 	g_string_append_printf (status_tooltip, ngettext ("There is %d update available",
 							  "There are %d updates available", length), length);
-#if GTK_CHECK_VERSION(2,15,0)
 	gtk_status_icon_set_tooltip_text (GTK_STATUS_ICON (cupdate->priv->sicon), status_tooltip->str);
-#else
-	gtk_status_icon_set_tooltip (GTK_STATUS_ICON (cupdate->priv->sicon), status_tooltip->str);
-#endif
+
 	/* if we are just refreshing after a failed update, don't try to do the actions */
 	if (!policy_action) {
 		egg_debug ("skipping actions");
@@ -822,17 +906,22 @@
 			goto out;
 		}
 
+		ret = pk_client_reset (cupdate->priv->client_primary, &error);
+		if (!ret) {
+			egg_warning ("cannot reset client: %s", error->message);
+			g_error_free (error);
+			goto out;
+		}
+
 		/* convert */
 		package_ids = pk_package_ids_from_array (security_array);
-		gpk_client_set_interaction (cupdate->priv->gclient_update_system, GPK_CLIENT_INTERACT_WARNING);
-		ret = gpk_client_update_packages (cupdate->priv->gclient_update_system, package_ids, &error);
+		ret = pk_client_update_packages (cupdate->priv->client_primary, package_ids, &error);
 		if (!ret) {
 			egg_warning ("Individual updates failed: %s", error->message);
 			g_error_free (error);
+		} else {
+			gpk_check_update_notify_doing_updates (cupdate);
 		}
-		/* this isn't valid anymore */
-		if (ret)
-			cupdate->priv->number_updates_critical_last_shown = 0;
 		g_strfreev (package_ids);
 		goto out;
 	}
@@ -840,15 +929,13 @@
 	/* just do everything */
 	if (update == GPK_UPDATE_ENUM_ALL) {
 		egg_debug ("we should do the update automatically!");
-		gpk_client_set_interaction (cupdate->priv->gclient_update_system, GPK_CLIENT_INTERACT_WARNING);
-		g_idle_add ((GSourceFunc) gpk_check_update_update_system, cupdate);
+		g_idle_add ((GSourceFunc) gpk_check_update_policy_all_idle_cb, cupdate);
 		goto out;
 	}
 
 	/* shouldn't happen */
 	egg_warning ("unknown update mode");
 out:
-	g_object_unref (list);
 	g_string_free (status_security, TRUE);
 	g_string_free (status_tooltip, TRUE);
 	g_ptr_array_foreach (security_array, (GFunc) g_free, NULL);
@@ -862,6 +949,7 @@
 static gboolean
 gpk_check_update_query_updates_idle_cb (GpkCheckUpdate *cupdate)
 {
+	egg_warning ("idle cb");
 	gpk_check_update_query_updates (cupdate, TRUE);
 	return FALSE;
 }
@@ -876,13 +964,7 @@
 
 	/* now try to get newest update list */
 	egg_warning ("updates changed");
-
-	/* ignore our own updates */
-	if (!cupdate->priv->get_updates_in_progress) {
-		g_idle_add ((GSourceFunc) gpk_check_update_query_updates_idle_cb, cupdate);
-		egg_warning ("not own updates");
-	} else
-		egg_warning ("own updates");
+	g_idle_add ((GSourceFunc) gpk_check_update_query_updates_idle_cb, cupdate);
 }
 
 /**
@@ -930,37 +1012,25 @@
 gpk_check_update_auto_refresh_cache_cb (GpkAutoRefresh *arefresh, GpkCheckUpdate *cupdate)
 {
 	gboolean ret;
-	g_return_if_fail (GPK_IS_CHECK_UPDATE (cupdate));
-
-	/* got a cache, no need to poll */
-	if (cupdate->priv->cache_okay)
-		return;
-
-	/* already in progress, but not yet certified okay */
-	if (cupdate->priv->cache_update_in_progress)
-		return;
+	GError *error = NULL;
 
-	cupdate->priv->cache_update_in_progress = TRUE;
-	cupdate->priv->cache_okay = TRUE;
+	g_return_if_fail (GPK_IS_CHECK_UPDATE (cupdate));
 
-	/* use the gnome helper to refresh the cache */
-	gpk_client_set_interaction (cupdate->priv->gclient_refresh_cache, GPK_CLIENT_INTERACT_NEVER);
-	ret = gpk_client_refresh_cache (cupdate->priv->gclient_refresh_cache, NULL);
+	ret = pk_client_reset (cupdate->priv->client_primary, &error);
 	if (!ret) {
-		/* we failed to get the cache */
-		egg_warning ("failed to refresh cache");
-
-		/* try again in a few minutes */
-		cupdate->priv->cache_okay = FALSE;
-	} else {
-		/* stop the polling */
-		cupdate->priv->cache_okay = TRUE;
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
 
-		/* now try to get updates */
-		egg_debug ("get updates");
-		gpk_check_update_query_updates (cupdate, TRUE);
+	ret = pk_client_refresh_cache (cupdate->priv->client_primary, TRUE, &error);
+	if (!ret) {
+		egg_warning ("cannot refresh cache: %s", error->message);
+		g_error_free (error);
+		goto out;
 	}
-	cupdate->priv->cache_update_in_progress = FALSE;
+out:
+	return;
 }
 
 /**
@@ -972,6 +1042,7 @@
 	g_return_if_fail (GPK_IS_CHECK_UPDATE (cupdate));
 
 	/* show the icon at login time */
+	egg_debug ("login cb");
 	g_idle_add ((GSourceFunc) gpk_check_update_query_updates_idle_cb, cupdate);
 }
 
@@ -981,9 +1052,34 @@
 static void
 gpk_check_update_auto_get_upgrades_cb (GpkAutoRefresh *arefresh, GpkCheckUpdate *cupdate)
 {
+	gboolean ret;
 	GError *error = NULL;
-	const GPtrArray	*array;
+
+	ret = pk_client_reset (cupdate->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	ret = pk_client_get_distro_upgrades (cupdate->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot get updates: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_check_update_process_distro_upgrades:
+ **/
+static void
+gpk_check_update_process_distro_upgrades (GpkCheckUpdate *cupdate, PkObjList *array)
+{
 	gboolean ret;
+	GError *error = NULL;
 	guint i;
 	PkDistroUpgradeObj *obj;
 	const gchar *title;
@@ -991,15 +1087,6 @@
 	GString *string = NULL;
 	g_return_if_fail (GPK_IS_CHECK_UPDATE (cupdate));
 
-	/* get updates */
-	gpk_client_set_interaction (cupdate->priv->gclient_get_distro_upgrades, GPK_CLIENT_INTERACT_NEVER);
-	array = gpk_client_get_distro_upgrades (cupdate->priv->gclient_get_distro_upgrades, &error);
-	if (array == NULL) {
-		egg_warning ("failed to get upgrades: %s", error->message);
-		g_error_free (error);
-		goto out;
-	}
-
 	/* any updates? */
 	if (array->len == 0) {
 		egg_debug ("no upgrades");
@@ -1016,7 +1103,7 @@
 	/* find the upgrade string */
 	string = g_string_new ("");
 	for (i=0; i < array->len; i++) {
-		obj = (PkDistroUpgradeObj *) g_ptr_array_index (array, i);
+		obj = (PkDistroUpgradeObj *) pk_obj_list_index (array, i);
 		g_string_append_printf (string, "%s (%s)\n", obj->name, pk_distro_upgrade_enum_to_text (obj->state));
 	}
 	if (string->len != 0)
@@ -1031,10 +1118,10 @@
 	}
 	notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
 	notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL);
-	notify_notification_add_action (notification, ACTION_DISTRO_UPGRADE_INFO,
+	notify_notification_add_action (notification, "distro-upgrade-info",
 					/* TRANSLATORS: provides more information about the upgrade */
 					_("More information"), gpk_check_update_libnotify_cb, cupdate, NULL);
-	notify_notification_add_action (notification, ACTION_DISTRO_UPGRADE_DO_NOT_SHOW,
+	notify_notification_add_action (notification, "distro-upgrade-do-not-show-available",
 					/* TRANSLATORS: hides forever */
 					_("Do not show this again"), gpk_check_update_libnotify_cb, cupdate, NULL);
 	ret = notify_notification_show (notification, &error);
@@ -1074,6 +1161,247 @@
 }
 
 /**
+ * gpk_check_update_error_code_cb:
+ **/
+static void
+gpk_check_update_error_code_cb (PkClient *client, PkErrorCodeEnum code, const gchar *details, GpkCheckUpdate *cupdate)
+{
+	/* ignore some errors */
+	if (code == PK_ERROR_ENUM_PROCESS_KILL ||
+	    code == PK_ERROR_ENUM_TRANSACTION_CANCELLED) {
+		egg_debug ("error ignored %s\n%s", pk_error_enum_to_text (code), details);
+		return;
+	}
+
+	/* ignore the ones we can handle */
+	if (code == PK_ERROR_ENUM_GPG_FAILURE) {
+		egg_debug ("error ignored as we're handling %s\n%s", pk_error_enum_to_text (code), details);
+		return;
+	}
+
+	/* not modal as we are a status icon */
+	gpk_error_dialog (gpk_error_enum_to_localised_text (code),
+			  gpk_error_enum_to_localised_message (code), details);
+}
+
+/**
+ * gpk_check_update_repo_signature_event_cb:
+ **/
+static void
+gpk_check_update_repo_signature_event_cb (GpkHelperRepoSignature *helper_repo_signature, GtkResponseType type, const gchar *key_id, const gchar *package_id, GpkCheckUpdate *cupdate)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (cupdate->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* install signature */
+	ret = pk_client_install_signature (cupdate->priv->client_secondary, PK_SIGTYPE_ENUM_GPG, key_id, package_id, &error);
+	if (!ret) {
+		egg_warning ("cannot install signature: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	/* set state */
+	egg_debug ("repo sig cb");
+	gpk_check_update_query_updates (cupdate, TRUE);
+out:
+	return;
+}
+
+/**
+ * gpk_check_update_repo_signature_required_cb:
+ **/
+static void
+gpk_check_update_repo_signature_required_cb (PkClient *client, const gchar *package_id, const gchar *repository_name,
+					      const gchar *key_url, const gchar *key_userid, const gchar *key_id,
+					      const gchar *key_fingerprint, const gchar *key_timestamp,
+					      PkSigTypeEnum type, GpkCheckUpdate *cupdate)
+{
+	/* use the helper */
+	gpk_helper_repo_signature_show (cupdate->priv->helper_repo_signature, package_id,
+					repository_name, key_url, key_userid, key_id, key_fingerprint, key_timestamp);
+}
+
+/**
+ * gpk_check_update_primary_requeue:
+ **/
+static gboolean
+gpk_check_update_primary_requeue (GpkCheckUpdate *cupdate)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* retry new action */
+	ret = pk_client_requeue (cupdate->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("Failed to requeue: %s", error->message);
+		g_error_free (error);
+	}
+	return ret;
+}
+
+/**
+ * gpk_check_update_finished_notify:
+ **/
+static void
+gpk_check_update_finished_notify (GpkCheckUpdate *cupdate, PkClient *client)
+{
+	gboolean ret;
+	GError *error = NULL;
+	NotifyNotification *notification;
+	PkRestartEnum restart;
+	guint i;
+	guint length;
+	PkPackageList *list;
+	const PkPackageObj *obj;
+	GString *message_text;
+	guint skipped_number = 0;
+	const gchar *message;
+
+	/* check we got some packages */
+	list = pk_client_get_package_list (client);
+	length = pk_package_list_get_size (list);
+	egg_debug ("length=%i", length);
+	if (length == 0) {
+		egg_debug ("no updates");
+		return;
+	}
+
+	message_text = g_string_new ("");
+
+	/* find any we skipped */
+	for (i=0; i<length; i++) {
+		obj = pk_package_list_get_obj (list, i);
+		egg_debug ("%s, %s, %s", pk_info_enum_to_text (obj->info),
+			  obj->id->name, obj->summary);
+		if (obj->info == PK_INFO_ENUM_BLOCKED) {
+			skipped_number++;
+			g_string_append_printf (message_text, "<b>%s</b> - %s\n",
+						obj->id->name, obj->summary);
+		}
+	}
+	g_object_unref (list);
+
+	/* notify the user if there were skipped entries */
+	if (skipped_number > 0) {
+		/* TRANSLATORS: we did the update, but some updates were skipped and not applied */
+		message = ngettext ("One package was skipped:",
+				    "Some packages were skipped:", skipped_number);
+		g_string_prepend (message_text, message);
+		g_string_append_c (message_text, '\n');
+	}
+
+	/* add a message that we need to restart */
+	restart = pk_client_get_require_restart (client);
+	if (restart != PK_RESTART_ENUM_NONE) {
+		message = gpk_restart_enum_to_localised_text (restart);
+
+		/* add a gap if we are putting both */
+		if (skipped_number > 0)
+			g_string_append (message_text, "\n");
+
+		g_string_append (message_text, message);
+		g_string_append_c (message_text, '\n');
+	}
+
+	/* trim off extra newlines */
+	if (message_text->len != 0)
+		g_string_set_size (message_text, message_text->len-1);
+
+	/* do we do the notification? */
+	ret = gconf_client_get_bool (cupdate->priv->gconf_client, GPK_CONF_NOTIFY_UPDATE_COMPLETE, NULL);
+	if (!ret) {
+		egg_debug ("ignoring due to GConf");
+		return;
+	}
+
+	/* TRANSLATORS: title: system update completed all okay */
+	notification = notify_notification_new (_("The system update has completed"), message_text->str, "help-browser", NULL);
+	notify_notification_set_timeout (notification, 15000);
+	notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+	if (restart == PK_RESTART_ENUM_SYSTEM) {
+		notify_notification_add_action (notification, "restart",
+						/* TRANSLATORS: restart computer as system packages need update */
+						_("Restart computer now"), gpk_check_update_libnotify_cb, cupdate, NULL);
+		notify_notification_add_action (notification, "do-not-show-complete-restart",
+						/* TRANSLATORS: don't show this option again (for restart) */
+						_("Do not show this again"), gpk_check_update_libnotify_cb, cupdate, NULL);
+	} else {
+		notify_notification_add_action (notification, "do-not-show-complete",
+						/* TRANSLATORS: don't show this option again (when finished)  */
+						_("Do not show this again"), gpk_check_update_libnotify_cb, cupdate, NULL);
+	}
+	ret = notify_notification_show (notification, &error);
+	if (!ret) {
+		egg_warning ("error: %s", error->message);
+		g_error_free (error);
+	}
+	g_string_free (message_text, TRUE);
+}
+
+/**
+ * gpk_check_update_finished_cb:
+ **/
+static void
+gpk_check_update_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkCheckUpdate *cupdate)
+{
+	PkRoleEnum role;
+	PkPackageList *list;
+	PkObjList *array;
+
+	pk_client_get_role (client, &role, NULL, NULL);
+	egg_debug ("role: %s, exit: %s", pk_role_enum_to_text (role), pk_exit_enum_to_text (exit_enum));
+
+	/* we've just agreed to auth */
+	if (role == PK_ROLE_ENUM_INSTALL_SIGNATURE) {
+		if (exit_enum == PK_EXIT_ENUM_SUCCESS)
+			gpk_check_update_primary_requeue (cupdate);
+	}
+
+	/* get-updates */
+	if (role == PK_ROLE_ENUM_GET_UPDATES &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		list = pk_client_get_package_list (client);
+		gpk_check_update_process_updates (cupdate, list, TRUE);
+		g_object_unref (list);
+	}
+
+	/* get-upgrades */
+	if (role == PK_ROLE_ENUM_GET_DISTRO_UPGRADES &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		array = pk_client_get_cached_objects (client);
+		gpk_check_update_process_distro_upgrades (cupdate, array);
+		g_object_unref (array);
+	}
+
+	/* refresh-cache */
+	if (role == PK_ROLE_ENUM_REFRESH_CACHE &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		egg_debug ("finished refresh cb");
+		gpk_check_update_query_updates (cupdate, TRUE);
+	}
+
+	/* updates */
+	if ((role == PK_ROLE_ENUM_UPDATE_PACKAGES ||
+	     role == PK_ROLE_ENUM_UPDATE_SYSTEM) &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		gpk_check_update_finished_notify (cupdate, client);
+		cupdate->priv->number_updates_critical_last_shown = 0;
+	}
+}
+
+/**
  * gpk_check_update_init:
  * @cupdate: This class instance
  **/
@@ -1088,7 +1416,11 @@
 	cupdate->priv->number_updates_critical_last_shown = 0;
 	cupdate->priv->sicon = gpk_smart_icon_new ();
 
+	/* preload all the common GConf keys */
 	cupdate->priv->gconf_client = gconf_client_get_default ();
+	gconf_client_add_dir (cupdate->priv->gconf_client, GPK_CONF_DIR,
+			      GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
 	cupdate->priv->arefresh = gpk_auto_refresh_new ();
 	g_signal_connect (cupdate->priv->arefresh, "refresh-cache",
 			  G_CALLBACK (gpk_check_update_auto_refresh_cache_cb), cupdate);
@@ -1115,11 +1447,26 @@
 	g_signal_connect (cupdate->priv->dbus_monitor_viewer, "connection-changed",
 			  G_CALLBACK (gpk_cupdate_connection_changed_cb), cupdate);
 
-	/* install stuff using the gnome helpers */
-	cupdate->priv->gclient_refresh_cache = gpk_client_new ();
-	cupdate->priv->gclient_update_system = gpk_client_new ();
-	cupdate->priv->gclient_get_updates = gpk_client_new ();
-	cupdate->priv->gclient_get_distro_upgrades = gpk_client_new ();
+	/* use an asynchronous query object */
+	cupdate->priv->client_primary = pk_client_new ();
+	pk_client_set_use_buffer (cupdate->priv->client_primary, TRUE, NULL);
+	g_signal_connect (cupdate->priv->client_primary, "finished",
+			  G_CALLBACK (gpk_check_update_finished_cb), cupdate);
+	g_signal_connect (cupdate->priv->client_primary, "error-code",
+			  G_CALLBACK (gpk_check_update_error_code_cb), cupdate);
+	g_signal_connect (cupdate->priv->client_primary, "repo-signature-required",
+			  G_CALLBACK (gpk_check_update_repo_signature_required_cb), cupdate);
+
+	/* this is for the auth callback */
+	cupdate->priv->client_secondary = pk_client_new ();
+	g_signal_connect (cupdate->priv->client_secondary, "error-code",
+			  G_CALLBACK (gpk_check_update_error_code_cb), cupdate);
+	g_signal_connect (cupdate->priv->client_secondary, "finished",
+			  G_CALLBACK (gpk_check_update_finished_cb), cupdate);
+
+	/* helpers */
+	cupdate->priv->helper_repo_signature = gpk_helper_repo_signature_new ();
+	g_signal_connect (cupdate->priv->helper_repo_signature, "event", G_CALLBACK (gpk_check_update_repo_signature_event_cb), NULL);
 
 	cupdate->priv->pconnection = pk_connection_new ();
 	g_signal_connect (cupdate->priv->pconnection, "connection-changed",
@@ -1140,11 +1487,6 @@
 	cupdate->priv->tlist = pk_task_list_new ();
 	g_signal_connect (cupdate->priv->tlist, "changed",
 			  G_CALLBACK (gpk_check_update_task_list_changed_cb), cupdate);
-
-	/* refresh the cache, and poll until we get a good refresh */
-	cupdate->priv->cache_okay = FALSE;
-	cupdate->priv->cache_update_in_progress = FALSE;
-	cupdate->priv->get_updates_in_progress = FALSE;
 }
 
 /**
@@ -1168,11 +1510,10 @@
 	g_object_unref (cupdate->priv->arefresh);
 	g_object_unref (cupdate->priv->gconf_client);
 	g_object_unref (cupdate->priv->control);
-	g_object_unref (cupdate->priv->gclient_refresh_cache);
-	g_object_unref (cupdate->priv->gclient_update_system);
-	g_object_unref (cupdate->priv->gclient_get_updates);
-	g_object_unref (cupdate->priv->gclient_get_distro_upgrades);
+	g_object_unref (cupdate->priv->client_primary);
+	g_object_unref (cupdate->priv->client_secondary);
 	g_object_unref (cupdate->priv->dbus_monitor_viewer);
+	g_object_unref (cupdate->priv->helper_repo_signature);
 	if (cupdate->priv->important_updates_array != NULL) {
 		g_ptr_array_foreach (cupdate->priv->important_updates_array, (GFunc) g_free, NULL);
 		g_ptr_array_free (cupdate->priv->important_updates_array, TRUE);

Modified: trunk/src/gpk-common.h
==============================================================================
--- trunk/src/gpk-common.h	(original)
+++ trunk/src/gpk-common.h	Tue Apr 14 16:28:59 2009
@@ -62,7 +62,8 @@
 #define GPK_CONF_APPLICATION_FILTER_NEWEST	"/apps/gnome-packagekit/application/filter_newest"
 #define GPK_CONF_APPLICATION_CATEGORY_GROUPS	"/apps/gnome-packagekit/application/category_groups"
 #define GPK_CONF_APPLICATION_SEARCH_MODE	"/apps/gnome-packagekit/application/search_mode"
-#define GPK_CONF_UPDATE_VIEWER_PRECACHE_DETAILS	"/apps/gnome-packagekit/update_viewer/precache_details"
+#define GPK_CONF_UPDATE_VIEWER_PRECACHE_DETAILS	"/apps/gnome-packagekit/update-viewer/precache_details"
+#define GPK_CONF_UPDATE_VIEWER_MOBILE_BBAND	"/apps/gnome-packagekit/update-viewer/notify_mobile_connection"
 #define GPK_CONF_IGNORED_MESSAGES		"/apps/gnome-packagekit/ignored_messages"
 
 #define GPK_CONF_ENABLE_FONT_HELPER		"/apps/gnome-packagekit/enable_font_helper"

Added: trunk/src/gpk-dbus-task.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-dbus-task.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,3338 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <unistd.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <fontconfig/fontconfig.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <polkit-gnome/polkit-gnome.h>
+#include <libnotify/notify.h>
+#include <packagekit-glib/packagekit.h>
+
+#include "egg-debug.h"
+#include "egg-string.h"
+
+#include "gpk-dbus.h"
+#include "gpk-dbus-task.h"
+#include "gpk-modal-dialog.h"
+#include "gpk-common.h"
+#include "gpk-gnome.h"
+#include "gpk-error.h"
+#include "gpk-language.h"
+#include "gpk-dialog.h"
+#include "gpk-vendor.h"
+#include "gpk-enum.h"
+#include "gpk-x11.h"
+#include "gpk-desktop.h"
+#include "gpk-helper-repo-signature.h"
+#include "gpk-helper-eula.h"
+#include "gpk-helper-run.h"
+#include "gpk-helper-untrusted.h"
+#include "gpk-helper-chooser.h"
+
+static void     gpk_dbus_task_finalize	(GObject	*object);
+
+#define GPK_DBUS_TASK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskPrivate))
+#define GPK_DBUS_TASK_FINISHED_AUTOCLOSE_DELAY	10 /* seconds */
+
+typedef enum {
+	GPK_DBUS_TASK_ROLE_IS_INSTALLED,
+	GPK_DBUS_TASK_ROLE_SEARCH_FILE,
+	GPK_DBUS_TASK_ROLE_INSTALL_PACKAGE_FILES,
+	GPK_DBUS_TASK_ROLE_INSTALL_PROVIDE_FILES,
+	GPK_DBUS_TASK_ROLE_INSTALL_MIME_TYPES,
+	GPK_DBUS_TASK_ROLE_INSTALL_GSTREAMER_RESOURCES,
+	GPK_DBUS_TASK_ROLE_INSTALL_FONTCONFIG_RESOURCES,
+	GPK_DBUS_TASK_ROLE_INSTALL_PACKAGE_NAMES,
+	GPK_DBUS_TASK_ROLE_INSTALL_CATALOGS,
+	GPK_DBUS_TASK_ROLE_UNKNOWN
+} GpkDbusTaskRole;
+
+/**
+ * GpkDbusTaskPrivate:
+ *
+ * Private #GpkDbusTask data
+ **/
+struct _GpkDbusTaskPrivate
+{
+	GdkWindow		*parent_window;
+	GConfClient		*gconf_client;
+	PkClient		*client_primary;
+	PkClient		*client_secondary;
+	PkDesktop		*desktop;
+	PkControl		*control;
+	PkExitEnum		 exit;
+	PkBitfield		 roles;
+	GpkLanguage		*language;
+	GpkModalDialog		*dialog;
+	GpkVendor		*vendor;
+	gboolean		 show_confirm_search;
+	gboolean		 show_confirm_deps;
+	gboolean		 show_confirm_install;
+	gboolean		 show_progress;
+	gboolean		 show_finished;
+	gboolean		 show_warning;
+	guint			 timestamp;
+	gchar			*parent_title;
+	gchar			*parent_icon_name;
+	gchar			*error_details;
+	gint			 timeout;
+	GpkHelperRepoSignature	*helper_repo_signature;
+	GpkHelperEula		*helper_eula;
+	GpkHelperRun		*helper_run;
+	GpkHelperUntrusted	*helper_untrusted;
+	GpkHelperChooser	*helper_chooser;
+	DBusGMethodInvocation	*context;
+	GpkDbusTaskRole		 role;
+	gchar			**package_ids;
+	gchar			**files;
+	PkErrorCodeEnum		 last_exit_code;
+};
+
+G_DEFINE_TYPE (GpkDbusTask, gpk_dbus_task, G_TYPE_OBJECT)
+
+/**
+ * gpk_dbus_task_set_interaction:
+ **/
+gboolean
+gpk_dbus_task_set_interaction (GpkDbusTask *task, PkBitfield interact)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+
+	task->priv->show_confirm_search = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH);
+	task->priv->show_confirm_deps = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS);
+	task->priv->show_confirm_install = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL);
+	task->priv->show_progress = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_PROGRESS);
+	task->priv->show_finished = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_FINISHED);
+	task->priv->show_warning = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_WARNING);
+
+	/* debug */
+	egg_debug ("confirm_search:%i, confirm_deps:%i, confirm_install:%i, progress:%i, finished:%i, warning:%i",
+		   task->priv->show_confirm_search, task->priv->show_confirm_deps,
+		   task->priv->show_confirm_install, task->priv->show_progress,
+		   task->priv->show_finished, task->priv->show_warning);
+
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_context:
+ **/
+gboolean
+gpk_dbus_task_set_context (GpkDbusTask *task, DBusGMethodInvocation *context)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+	g_return_val_if_fail (context != NULL, FALSE);
+
+	task->priv->context = context;
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_timeout:
+ **/
+gboolean
+gpk_dbus_task_set_timeout (GpkDbusTask *task, gint timeout)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+
+	task->priv->timeout = timeout;
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_xid:
+ **/
+gboolean
+gpk_dbus_task_set_xid (GpkDbusTask *task, guint32 xid)
+{
+	GdkDisplay *display;
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+
+	display = gdk_display_get_default ();
+	task->priv->parent_window = gdk_window_foreign_new_for_display (display, xid);
+	egg_debug ("parent_window=%p", task->priv->parent_window);
+	gpk_modal_dialog_set_parent (task->priv->dialog, task->priv->parent_window);
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_timestamp:
+ **/
+gboolean
+gpk_dbus_task_set_timestamp (GpkDbusTask *task, guint32 timestamp)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+	task->priv->timestamp = timestamp;
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_repo_signature_event_cb:
+ **/
+static void
+gpk_dbus_task_repo_signature_event_cb (GpkHelperRepoSignature *helper_repo_signature, GtkResponseType type, const gchar *key_id, const gchar *package_id, GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (task->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* install signature */
+	ret = pk_client_install_signature (task->priv->client_secondary, PK_SIGTYPE_ENUM_GPG, key_id, package_id, &error);
+	if (!ret) {
+		egg_warning ("cannot install signature: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_eula_event_cb:
+ **/
+static void
+gpk_dbus_task_eula_event_cb (GpkHelperEula *helper_eula, GtkResponseType type, const gchar *eula_id, GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	if (type != GTK_RESPONSE_YES) {
+		goto out;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (task->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* install signature */
+	ret = pk_client_accept_eula (task->priv->client_secondary, eula_id, &error);
+	if (!ret) {
+		egg_warning ("cannot accept eula: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_eula_cb:
+ **/
+static void
+gpk_dbus_task_eula_required_cb (PkClient *client, const gchar *eula_id, const gchar *package_id,
+				    const gchar *vendor_name, const gchar *license_agreement, GpkDbusTask *task)
+{
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CUSTOM, pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR));
+	gpk_modal_dialog_set_title (task->priv->dialog, _("EULA required"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_SIG_CHECK);
+	gpk_modal_dialog_set_percentage (task->priv->dialog, 101);
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* use the helper */
+	gpk_helper_eula_show (task->priv->helper_eula, eula_id, package_id, vendor_name, license_agreement);
+}
+
+/**
+ * gpk_dbus_task_repo_signature_required_cb:
+ **/
+static void
+gpk_dbus_task_repo_signature_required_cb (PkClient *client, const gchar *package_id, const gchar *repository_name,
+					      const gchar *key_url, const gchar *key_userid, const gchar *key_id,
+					      const gchar *key_fingerprint, const gchar *key_timestamp,
+					      PkSigTypeEnum type, GpkDbusTask *task)
+{
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CUSTOM, pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR));
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Signature required"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_SIG_CHECK);
+	gpk_modal_dialog_set_percentage (task->priv->dialog, 101);
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* use the helper */
+	gpk_helper_repo_signature_show (task->priv->helper_repo_signature, package_id, repository_name, key_url, key_userid, key_id, key_fingerprint, key_timestamp);
+}
+
+static void gpk_dbus_task_install_package_files_internal (GpkDbusTask *task, gboolean trusted);
+
+/**
+ * gpk_dbus_task_untrusted_event_cb:
+ **/
+static void
+gpk_dbus_task_untrusted_event_cb (GpkHelperUntrusted *helper_untrusted, GtkResponseType type, GpkDbusTask *task)
+{
+	GError *error = NULL;
+	const gchar *title;
+
+	if (type != GTK_RESPONSE_YES) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to download");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	title = _("Install untrusted");
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+
+	/* install trusted */
+	gpk_dbus_task_install_package_files_internal (task, FALSE);
+out:
+	if (error != NULL)
+		g_error_free (error);
+	return;
+}
+
+static void gpk_dbus_task_install_package_ids_dep_check (GpkDbusTask *task);
+
+/**
+ * gpk_dbus_task_chooser_event_cb:
+ **/
+static void
+gpk_dbus_task_chooser_event_cb (GpkHelperChooser *helper_chooser, GtkResponseType type, const gchar *package_id, GpkDbusTask *task)
+{
+	GError *error = NULL;
+
+	/* selected nothing */
+	if (type != GTK_RESPONSE_YES || package_id == NULL) {
+
+		/* failed */
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not choose anything to install");
+		dbus_g_method_return_error (task->priv->context, error);
+
+		if (task->priv->show_warning) {
+			gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: we failed to install */
+			gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to install software"));
+			/* TRANSLATORS: we didn't select any applications that were returned */
+			gpk_modal_dialog_set_message (task->priv->dialog, _("No applications were chosen to be installed"));
+			gpk_modal_dialog_present (task->priv->dialog);
+			gpk_modal_dialog_run (task->priv->dialog);
+		}
+		goto out;
+	}
+
+	/* install this specific package */
+	task->priv->package_ids = pk_package_ids_from_id (package_id);
+
+	/* install these packages with deps */
+	gpk_dbus_task_install_package_ids_dep_check (task);
+
+out:
+	if (error != NULL)
+		g_error_free (error);
+	return;
+}
+
+/**
+ * gpk_dbus_task_libnotify_cb:
+ **/
+static void
+gpk_dbus_task_libnotify_cb (NotifyNotification *notification, gchar *action, gpointer data)
+{
+	GpkDbusTask *task = GPK_DBUS_TASK (data);
+
+	if (egg_strequal (action, "show-error-details")) {
+		/* TRANSLATORS: detailed text about the error */
+		gpk_error_dialog (_("Error details"), _("Package Manager error details"), task->priv->error_details);
+	} else {
+		egg_warning ("unknown action id: %s", action);
+	}
+}
+
+/**
+ * gpk_dbus_task_error_msg:
+ **/
+static void
+gpk_dbus_task_error_msg (GpkDbusTask *task, const gchar *title, GError *error)
+{
+	GtkWindow *window;
+	/* TRANSLATORS: default fallback error -- this should never happen */
+	const gchar *message = _("Unknown error. Please refer to the detailed report and report in your distribution bugtracker.");
+	const gchar *details = NULL;
+
+	if (!task->priv->show_warning)
+		return;
+
+	/* setup UI */
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+
+	/* print a proper error if we have it */
+	if (error != NULL) {
+		if (error->code == PK_CLIENT_ERROR_FAILED_AUTH ||
+		    g_str_has_prefix (error->message, "org.freedesktop.packagekit.")) {
+			/* TRANSLATORS: failed authentication */
+			message = _("You don't have the necessary privileges to perform this action.");
+			gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-permissions");
+		} else if (error->code == PK_CLIENT_ERROR_CANNOT_START_DAEMON) {
+			/* TRANSLATORS: could not start system service */
+			message = _("The packagekitd service could not be started.");
+			gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-no-service");
+		} else if (error->code == PK_CLIENT_ERROR_INVALID_INPUT) {
+			/* TRANSLATORS: the user tried to query for something invalid */
+			message = _("The query is not valid.");
+			details = error->message;
+		} else if (error->code == PK_CLIENT_ERROR_INVALID_FILE) {
+			/* TRANSLATORS: the user tried to install a file that was not compatable or broken */
+			message = _("The file is not valid.");
+			details = error->message;
+		} else {
+			details = error->message;
+		}
+	}
+
+	/* it's a normal UI, not a backtrace so keep in the UI */
+	if (details == NULL) {
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_message (task->priv->dialog, message);
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		gpk_modal_dialog_run (task->priv->dialog);
+		return;
+	}
+
+	/* hide the main window */
+	window = gpk_modal_dialog_get_window (task->priv->dialog);
+	gpk_error_dialog_modal_with_time (window, title, message, details, task->priv->timestamp);
+}
+
+/**
+ * gpk_dbus_task_install_package_ids:
+ * @task: a valid #GpkDbusTask instance
+ * @package_id: a package_id such as <literal>hal-info;0.20;i386;fedora</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static void
+gpk_dbus_task_install_package_ids (GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: title: installing packages */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Installing packages"));
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this should never happen, low level failure */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client to perform action"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	ret = pk_client_install_packages (task->priv->client_primary, task->priv->package_ids, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: error: failed to install, detailed error follows */
+		gpk_dbus_task_error_msg (task, _("Failed to install package"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_install_package_ids_dep_check:
+ * @task: a valid #GpkDbusTask instance
+ * @package_id: a package_id such as <literal>hal-info;0.20;i386;fedora</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static void
+gpk_dbus_task_install_package_ids_dep_check (GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (task->priv->package_ids != NULL);
+
+	/* are we dumb and can't check for depends? */
+	if (!pk_bitfield_contain (task->priv->roles, PK_ROLE_ENUM_GET_DEPENDS)) {
+		egg_warning ("skipping depends check");
+		gpk_dbus_task_install_package_ids (task);
+		goto out;
+	}
+
+	/* have we previously said we don't want to be shown the confirmation */
+	ret = gconf_client_get_bool (task->priv->gconf_client, GPK_CONF_SHOW_DEPENDS, NULL);
+	if (!ret) {
+		egg_warning ("we've said we don't want the dep dialog");
+		gpk_dbus_task_install_package_ids (task);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_deps) {
+		egg_warning ("skip confirm as not allowed to interact with user");
+		gpk_dbus_task_install_package_ids (task);
+		goto out;
+	}
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: finding a list of packages that we would also need to download */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Finding other packages we require"));
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-finding-depends");
+
+	/* setup the UI */
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this is an internal error, and should not be seen */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* find out if this would drag in other packages */
+	ret = pk_client_get_depends (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED), task->priv->package_ids, TRUE, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: error: could not get the extra package list when installing a package */
+		gpk_dbus_task_error_msg (task, _("Could not work out what packages would be also installed"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* wait for async reply */
+
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_error_from_exit_enum:
+ **/
+static GError *
+gpk_dbus_task_error_from_exit_enum (PkExitEnum exit)
+{
+	GError *error = NULL;
+
+	/* trivial case */
+	if (exit == PK_EXIT_ENUM_SUCCESS)
+		goto out;
+
+	/* set the correct error type */
+	if (exit == PK_EXIT_ENUM_FAILED)
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "Unspecified failure");
+	else if (exit == PK_EXIT_ENUM_CANCELLED)
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "Transaction was cancelled");
+	else if (exit == PK_EXIT_ENUM_KEY_REQUIRED)
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "A key was required but not provided");
+	else if (exit == PK_EXIT_ENUM_EULA_REQUIRED)
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "A EULA was not agreed to");
+	else if (exit == PK_EXIT_ENUM_KILLED)
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "The transaction was killed");
+	else
+		egg_error ("unknown exit code");
+out:
+	return error;
+}
+
+/**
+ * gpk_dbus_task_install_package_ids_dep_check_idle_cb:
+ **/
+static gboolean
+gpk_dbus_task_install_package_ids_dep_check_idle_cb (GpkDbusTask *task)
+{
+	egg_warning ("idle add install package ids dep check");
+	gpk_dbus_task_install_package_ids_dep_check (task);
+	return FALSE;
+}
+
+/**
+ * gpk_dbus_task_install_package_ids_idle_cb:
+ **/
+static gboolean
+gpk_dbus_task_install_package_ids_idle_cb (GpkDbusTask *task)
+{
+	egg_warning ("idle add install package ids");
+	gpk_dbus_task_install_package_ids (task);
+	return FALSE;
+}
+
+/**
+ * gpk_dbus_task_finished_cb:
+ **/
+static void
+gpk_dbus_task_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkDbusTask *task)
+{
+	PkRoleEnum role = PK_ROLE_ENUM_UNKNOWN;
+	gboolean ret;
+	guint len;
+	guint i;
+	const gchar *name = NULL;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	PkPackageList *list = NULL;
+	const PkPackageObj *obj;
+	gboolean already_installed = FALSE;
+	gchar *title = NULL;
+	gchar *message = NULL;
+	gchar *text = NULL;
+	PkPackageId *id = NULL;
+	gchar *info_url = NULL;
+	gchar **package_ids = NULL;
+	GtkResponseType button;
+	gchar *package_id = NULL;
+
+	/* get role */
+	pk_client_get_role (client, &role, NULL, NULL);
+	egg_debug ("role: %s, exit: %s", pk_role_enum_to_text (role), pk_exit_enum_to_text (exit_enum));
+
+	/* stop spinning */
+	gpk_modal_dialog_set_percentage (task->priv->dialog, 100);
+
+	/* we failed because we're handling the auth, just ignore */
+	if (client == task->priv->client_primary &&
+	    (exit_enum == PK_EXIT_ENUM_KEY_REQUIRED ||
+	     exit_enum == PK_EXIT_ENUM_EULA_REQUIRED)) {
+		egg_debug ("ignoring primary sig-required or eula");
+		goto out;
+	}
+
+	/* EULA or GPG key auth done */
+	if (client == task->priv->client_secondary &&
+	    exit_enum == PK_EXIT_ENUM_SUCCESS) {
+
+		/* try again */
+		ret = pk_client_requeue (task->priv->client_primary, &error_local);
+		if (!ret) {
+			egg_warning ("Failed to requeue: %s", error_local->message);
+			error = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "cannot requeue: %s", error_local->message);
+			dbus_g_method_return_error (task->priv->context, error);
+		}
+		goto out;
+	}
+
+	if (exit_enum != PK_EXIT_ENUM_SUCCESS) {
+
+		/* we failed because of failed exit code */
+		if (task->priv->last_exit_code == PK_ERROR_ENUM_GPG_FAILURE ||
+		    task->priv->last_exit_code == PK_ERROR_ENUM_BAD_GPG_SIGNATURE ||
+		    task->priv->last_exit_code == PK_ERROR_ENUM_MISSING_GPG_SIGNATURE) {
+			egg_warning ("showing untrusted ui");
+			gpk_helper_untrusted_show (task->priv->helper_untrusted, task->priv->last_exit_code);
+			goto out;
+		}
+
+		/* show finished? */
+		if (!task->priv->show_finished)
+			gpk_modal_dialog_close (task->priv->dialog);
+
+		/* fail the transaction and set the correct error */
+		error = gpk_dbus_task_error_from_exit_enum (exit_enum);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* from InstallMimeTypes */
+	if (task->priv->role == GPK_DBUS_TASK_ROLE_INSTALL_MIME_TYPES &&
+	    role == PK_ROLE_ENUM_WHAT_PROVIDES) {
+
+		/* found nothing? */
+		list = pk_client_get_package_list (task->priv->client_primary);
+		len = pk_package_list_get_size (list);
+		if (len == 0) {
+			if (task->priv->show_warning) {
+				info_url = gpk_vendor_get_not_found_url (task->priv->vendor, GPK_VENDOR_URL_TYPE_MIME);
+				/* only show the "more info" button if there is a valid link */
+				if (info_url != NULL)
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+				else
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				/* TRANSLATORS: title */
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to find software"));
+				/* TRANSLATORS: nothing found in the software sources that helps */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("No new applications can be found to handle this type of file"));
+				gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-package-not-found");
+				/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+				gpk_modal_dialog_set_action (task->priv->dialog, _("More information"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				button = gpk_modal_dialog_run (task->priv->dialog);
+				if (button == GTK_RESPONSE_OK)
+					gpk_gnome_open (info_url);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "nothing was found to handle mime type");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* populate a chooser */
+		gpk_helper_chooser_show (task->priv->helper_chooser, list);
+		goto out;
+	}
+
+	/* from InstallProvideFiles */
+	if (task->priv->role == GPK_DBUS_TASK_ROLE_INSTALL_PROVIDE_FILES &&
+	    role == PK_ROLE_ENUM_SEARCH_FILE) {
+		/* found nothing? */
+		list = pk_client_get_package_list (task->priv->client_primary);
+		len = pk_package_list_get_size (list);
+		if (len == 0) {
+			if (task->priv->show_warning) {
+				info_url = gpk_vendor_get_not_found_url (task->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT);
+				/* only show the "more info" button if there is a valid link */
+				if (info_url != NULL)
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+				else
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				/* TRANSLATORS: failed to fild the package for thefile */
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to find package"));
+				/* TRANSLATORS: nothing found */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("The file could not be found in any packages"));
+				gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-package-not-found");
+				/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+				gpk_modal_dialog_set_action (task->priv->dialog, _("More information"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				button = gpk_modal_dialog_run (task->priv->dialog);
+				if (button == GTK_RESPONSE_OK)
+					gpk_gnome_open (info_url);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "no files found");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* see what we've got already */
+		for (i=0; i<len; i++) {
+			obj = pk_package_list_get_obj (list, i);
+			if (obj->info == PK_INFO_ENUM_INSTALLED) {
+				already_installed = TRUE;
+				id = obj->id;
+			} else if (obj->info == PK_INFO_ENUM_AVAILABLE) {
+				egg_debug ("package '%s' resolved to:", obj->id->name);
+				id = obj->id;
+			}
+		}
+
+		/* already installed? */
+		if (already_installed) {
+			if (task->priv->show_warning) {
+				/* TRANSLATORS: we've already got a package that provides this file */
+				text = g_strdup_printf (_("The %s package already provides this file"), id->name);
+				gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				/* TRANSLATORS: title */
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to install file"));
+				gpk_modal_dialog_set_message (task->priv->dialog, text);
+				gpk_modal_dialog_present (task->priv->dialog);
+				gpk_modal_dialog_run (task->priv->dialog);
+				g_free (text);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "already provided");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* install this specific package */
+		package_id = pk_package_id_to_string (id);
+		/* convert to data */
+		task->priv->package_ids = pk_package_ids_from_id (package_id);
+
+		/* install these packages with deps */
+		g_idle_add ((GSourceFunc) gpk_dbus_task_install_package_ids_dep_check_idle_cb, task);
+		goto out;
+	}
+
+	/* from InstallPackageIds */
+	if (role == PK_ROLE_ENUM_GET_DEPENDS) {
+		/* these are the new packages */
+		list = pk_client_get_package_list (task->priv->client_primary);
+		len = pk_package_list_get_size (list);
+		if (len == 0) {
+			egg_debug ("no deps");
+			goto skip_checks;
+		}
+
+		/* TRANSLATORS: title: tell the user we have to install additional packages */
+		title = g_strdup_printf (ngettext ("%i additional package also has to be installed",
+						   "%i additional packages also have to be installed",
+						   len), len);
+
+		/* message */
+		text = gpk_dialog_package_id_name_join_locale (task->priv->package_ids);
+		/* TRANSLATORS: message: explain to the user what we are doing in more detail */
+		message = g_strdup_printf (ngettext ("To install %s, an additional package also has to be downloaded.",
+						     "To install %s, additional packages also have to be downloaded.",
+						     len), text);
+		g_free (text);
+
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+		gpk_modal_dialog_set_package_list (task->priv->dialog, list);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_message (task->priv->dialog, message);
+		/* TRANSLATORS: title: installing package */
+		gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+		gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-install-other-packages");
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		button = gpk_modal_dialog_run (task->priv->dialog);
+
+		/* did we click no or exit the window? */
+		if (button != GTK_RESPONSE_OK) {
+			gpk_modal_dialog_close (task->priv->dialog);
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to additional deps");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+skip_checks:
+		g_idle_add ((GSourceFunc) gpk_dbus_task_install_package_ids_idle_cb, task);
+	}
+
+	/* from InstallPackageIds */
+	if (role == PK_ROLE_ENUM_INSTALL_PACKAGES ||
+	    role == PK_ROLE_ENUM_INSTALL_FILES) {
+
+		/* show summary? */
+		if (task->priv->show_finished) {
+			list = pk_client_get_package_list (client);
+			/* TRANSLATORS: list the packages we just installed */
+			gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_FINISHED, GPK_MODAL_DIALOG_PACKAGE_LIST);
+			gpk_modal_dialog_set_message (task->priv->dialog, _("The following packages were installed:"));
+
+			/* filter out installed */
+			for (i=0; i<PK_OBJ_LIST(list)->len; i++) {
+				obj = pk_obj_list_index (PK_OBJ_LIST (list), i);
+				if (obj->info != PK_INFO_ENUM_INSTALLING) {
+					pk_obj_list_remove_index (PK_OBJ_LIST (list), i);
+					i--;
+				}
+			}
+			gpk_modal_dialog_set_package_list (task->priv->dialog, list);
+			gpk_modal_dialog_present (task->priv->dialog);
+			g_object_unref (list);
+		} else {
+			gpk_modal_dialog_close (task->priv->dialog);
+		}
+
+		/* done! */
+		egg_warning ("doing async return");
+		dbus_g_method_return (task->priv->context, TRUE); /* FIXME: we send true? */
+		goto out;
+	}
+
+	/* IsInstalled */
+	if (task->priv->role == GPK_DBUS_TASK_ROLE_IS_INSTALLED) {
+		list = pk_client_get_package_list (task->priv->client_primary);
+
+		/* one or more entry? */
+		ret = (PK_OBJ_LIST(list)->len > 0);
+		egg_warning ("doing async return");
+		dbus_g_method_return (task->priv->context, ret);
+		goto out;
+	}
+
+	/* SearchFile */
+	if (task->priv->role == GPK_DBUS_TASK_ROLE_SEARCH_FILE) {
+		list = pk_client_get_package_list (task->priv->client_primary);
+
+		/* one or more entry? */
+		len = PK_OBJ_LIST(list)->len;
+		if (len > 0)
+			name = pk_package_list_get_obj (list, 0)->id->name;
+		egg_warning ("doing async return");
+		dbus_g_method_return (task->priv->context, (len > 0), name);
+		goto out;
+	}
+
+	/* InstallPackageNames */
+	if (task->priv->role == GPK_DBUS_TASK_ROLE_INSTALL_PACKAGE_NAMES &&
+	    role == PK_ROLE_ENUM_RESOLVE) {
+
+		/* found nothing? */
+		list = pk_client_get_package_list (task->priv->client_primary);
+		len = pk_package_list_get_size (list);
+		if (len == 0) {
+			if (task->priv->show_warning) {
+				//FIXME: shows package_id in UI
+				/* TRANSLATORS: couldn't resolve name to package */
+				title = g_strdup_printf (_("Could not find packages"));
+				info_url = gpk_vendor_get_not_found_url (task->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT);
+				/* only show the "more info" button if there is a valid link */
+				if (info_url != NULL)
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+				else
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				gpk_modal_dialog_set_title (task->priv->dialog, title);
+				/* TRANSLATORS: message: could not find */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("The packages could not be found in any software source"));
+				gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-package-not-found");
+				/* TRANSLATORS: button: a link to the help file */
+				gpk_modal_dialog_set_action (task->priv->dialog, _("More information"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				button = gpk_modal_dialog_run (task->priv->dialog);
+				if (button == GTK_RESPONSE_OK)
+					gpk_gnome_open (info_url);
+				g_free (info_url);
+				g_free (title);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "no package found");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* see what we've got already */
+		for (i=0; i<len; i++) {
+			obj = pk_package_list_get_obj (list, i);
+			if (obj->info == PK_INFO_ENUM_INSTALLED) {
+				already_installed = TRUE;
+			} else if (obj->info == PK_INFO_ENUM_AVAILABLE) {
+				egg_debug ("package '%s' resolved", obj->id->name);
+				id = obj->id;
+				//TODO: we need to list these in a gpk-dbus_task-chooser
+			}
+		}
+
+		/* already installed? */
+		if (already_installed) {
+			if (task->priv->show_warning) {
+				//FIXME: shows package_id in UI
+				/* TRANSLATORS: title: package is already installed */
+				gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to install packages"));
+				/* TRANSLATORS: message: package is already installed */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("The package is already installed"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				gpk_modal_dialog_run (task->priv->dialog);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "package already found");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* got junk? */
+		if (id == NULL) {
+			if (task->priv->show_warning) {
+				gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				/* TRANSLATORS: failed to install, shouldn't be shown */
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to install package"));
+				/* TRANSLATORS: the search gave us the wrong result. internal error. barf. */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("Incorrect response from search"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				gpk_modal_dialog_run (task->priv->dialog);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "incorrect response from search");
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* convert to data */
+		task->priv->package_ids = pk_package_list_to_strv (list);
+
+		/* install these packages with deps */
+		g_idle_add ((GSourceFunc) gpk_dbus_task_install_package_ids_dep_check_idle_cb, task);
+		goto out;
+	}
+
+out:
+	g_free (info_url);
+	g_free (package_id);
+	g_strfreev (package_ids);
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+	if (list != NULL)
+		g_object_unref (list);
+}
+
+/**
+ * gpk_dbus_task_set_status:
+ **/
+static gboolean
+gpk_dbus_task_set_status (GpkDbusTask *task, PkStatusEnum status)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+
+	/* do we force progress? */
+	if (!task->priv->show_progress) {
+		if (status == PK_STATUS_ENUM_DOWNLOAD_REPOSITORY ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_FILELIST ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_CHANGELOG ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_GROUP ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO ||
+		    status == PK_STATUS_ENUM_REFRESH_CACHE) {
+			gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+			gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-progress");
+			gpk_modal_dialog_present_with_time (task->priv->dialog, 0);
+		}
+	}
+
+	/* ignore */
+	if (!task->priv->show_progress) {
+		egg_warning ("not showing progress");
+		return FALSE;
+	}
+
+	/* set icon */
+	gpk_modal_dialog_set_image_status (task->priv->dialog, status);
+
+	/* set label */
+	gpk_modal_dialog_set_title (task->priv->dialog, gpk_status_enum_to_localised_text (status));
+
+	/* spin */
+	if (status == PK_STATUS_ENUM_WAIT)
+		gpk_modal_dialog_set_percentage (task->priv->dialog, PK_CLIENT_PERCENTAGE_INVALID);
+
+	/* do visual stuff when finished */
+	if (status == PK_STATUS_ENUM_FINISHED) {
+		/* make insensitive */
+		gpk_modal_dialog_set_allow_cancel (task->priv->dialog, FALSE);
+
+		/* stop spinning */
+		gpk_modal_dialog_set_percentage (task->priv->dialog, 100);
+	}
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_progress_changed_cb:
+ **/
+static void
+gpk_dbus_task_progress_changed_cb (PkClient *client, guint percentage, guint subpercentage,
+				guint elapsed, guint remaining, GpkDbusTask *task)
+{
+	/* ignore */
+	gpk_modal_dialog_set_percentage (task->priv->dialog, percentage);
+	gpk_modal_dialog_set_remaining (task->priv->dialog, remaining);
+}
+
+/**
+ * gpk_dbus_task_status_changed_cb:
+ **/
+static void
+gpk_dbus_task_status_changed_cb (PkClient *client, PkStatusEnum status, GpkDbusTask *task)
+{
+	gpk_dbus_task_set_status (task, status);
+}
+
+/**
+ * gpk_dbus_task_error_code_cb:
+ **/
+static void
+gpk_dbus_task_error_code_cb (PkClient *client, PkErrorCodeEnum code, const gchar *details, GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+	const gchar *title;
+	const gchar *message;
+	NotifyNotification *notification;
+	GtkWidget *widget;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	/* save for later */
+	task->priv->last_exit_code = code;
+
+	/* have we handled? */
+	if (code == PK_ERROR_ENUM_GPG_FAILURE ||
+	    code == PK_ERROR_ENUM_NO_LICENSE_AGREEMENT) {
+		egg_warning ("did not auth, but should be already handled");
+		return;
+	}
+
+	/* have we handled? */
+	if (code == PK_ERROR_ENUM_BAD_GPG_SIGNATURE ||
+	    code == PK_ERROR_ENUM_MISSING_GPG_SIGNATURE) {
+		egg_warning ("will handled in finished");
+		return;
+	}
+
+	/* ignore some errors */
+	if (code == PK_ERROR_ENUM_PROCESS_KILL ||
+	    code == PK_ERROR_ENUM_TRANSACTION_CANCELLED) {
+		egg_debug ("error ignored %s\n%s", pk_error_enum_to_text (code), details);
+		return;
+	}
+
+	egg_debug ("code was %s", pk_error_enum_to_text (code));
+
+	/* use a modal dialog if showing progress, else use libnotify */
+	title = gpk_error_enum_to_localised_text (code);
+	message = gpk_error_enum_to_localised_message (code);
+	if (task->priv->show_progress) {
+		widget = GTK_WIDGET (gpk_modal_dialog_get_window (task->priv->dialog));
+		gpk_error_dialog_modal (GTK_WINDOW (widget), title, message, details);
+		return;
+	}
+
+	/* save this globally */
+	g_free (task->priv->error_details);
+	task->priv->error_details = g_markup_escape_text (details, -1);
+
+	/* do the bubble */
+	notification = notify_notification_new (title, message, "help-browser", NULL);
+	notify_notification_set_timeout (notification, 15000);
+	notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+	notify_notification_add_action (notification, "show-error-details",
+					/* TRANSLATORS: button: show details about the error */
+					_("Show details"), gpk_dbus_task_libnotify_cb, task, NULL);
+	ret = notify_notification_show (notification, &error);
+	if (!ret) {
+		egg_warning ("error: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+/**
+ * gpk_dbus_task_package_cb:
+ **/
+static void
+gpk_dbus_task_package_cb (PkClient *client, const PkPackageObj *obj, GpkDbusTask *task)
+{
+	gchar *text;
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	if (!task->priv->show_progress)
+		return;
+
+	text = gpk_package_id_format_twoline (obj->id, obj->summary);
+	gpk_modal_dialog_set_message (task->priv->dialog, text);
+	g_free (text);
+}
+
+/**
+ * gpk_dbus_task_allow_cancel_cb:
+ **/
+static void
+gpk_dbus_task_allow_cancel_cb (PkClient *client, gboolean allow_cancel, GpkDbusTask *task)
+{
+	gpk_modal_dialog_set_allow_cancel (task->priv->dialog, allow_cancel);
+}
+
+/**
+ * gpk_dbus_task_button_close_cb:
+ **/
+static void
+gpk_dbus_task_button_close_cb (GtkWidget *widget, GpkDbusTask *task)
+{
+	/* close, don't abort */
+	gpk_modal_dialog_close (task->priv->dialog);
+}
+
+/**
+ * gpk_dbus_task_button_cancel_cb:
+ **/
+static void
+gpk_dbus_task_button_cancel_cb (GtkWidget *widget, GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* we might have a transaction running */
+	ret = pk_client_cancel (task->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to cancel client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	ret = pk_client_cancel (task->priv->client_secondary, &error);
+	if (!ret) {
+		egg_warning ("failed to cancel client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_internal:
+ **/
+static void
+gpk_dbus_task_install_package_files_internal (GpkDbusTask *task, gboolean trusted)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	guint length;
+	const gchar *title;
+
+	/* FIXME: we need to move this into PkClient sooner or later */
+	task->priv->last_exit_code = PK_ERROR_ENUM_UNKNOWN;
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this should never happen, low level failure */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client to perform action"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* install local file */
+	ret = pk_client_install_files (task->priv->client_primary, trusted, task->priv->files, &error_local);
+	if (!ret) {
+		length = g_strv_length (task->priv->files);
+		/* TRANSLATORS: title: detailed internal error why the file install failed */
+		title = ngettext ("Failed to install file", "Failed to install files", length);
+		gpk_dbus_task_error_msg (task, title, error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_ptr_array_to_bullets:
+ *
+ * splits the strings up nicely
+ *
+ * Return value: a newly allocated string
+ **/
+static gchar *
+gpk_dbus_task_ptr_array_to_bullets (GPtrArray *array, const gchar *prefix)
+{
+	GString *string;
+	guint i;
+	gchar *text;
+
+	/* don't use a bullet for one item */
+	if (array->len == 1) {
+		if (prefix != NULL)
+			return g_strdup_printf ("%s\n\n%s", prefix, (const gchar *) g_ptr_array_index (array, 0));
+		else
+			return g_strdup (g_ptr_array_index (array, 0));
+	}
+
+	string = g_string_new (prefix);
+	if (prefix != NULL)
+		g_string_append (string, "\n\n");
+
+	/* prefix with bullet and suffix with newline */
+	for (i=0; i<array->len; i++) {
+		text = (gchar *) g_ptr_array_index (array, i);
+		g_string_append_printf (string, "â %s\n", text);
+	}
+
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	text = g_string_free (string, FALSE);
+	return text;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_get_user_temp:
+ *
+ * Return (and create if does not exist) a temporary directory
+ * that is writable only by the user, and readable by root.
+ *
+ * Return value: the temp directory, or %NULL for create error
+ **/
+static gchar *
+gpk_dbus_task_install_package_files_get_user_temp (GpkDbusTask *task, const gchar *subfolder, GError **error)
+{
+	GFile *file;
+	gboolean ret;
+	gchar *path = NULL;
+
+	/* build path in home folder */
+	path = g_build_filename (g_get_home_dir (), ".PackageKit", subfolder, NULL);
+
+	/* find if exists */
+	file = g_file_new_for_path (path);
+	ret = g_file_query_exists (file, NULL);
+	if (ret)
+		goto out;
+
+	/* create as does not exist */
+	ret = g_file_make_directory_with_parents (file, NULL, error);
+	g_object_unref (file);
+	if (!ret) {
+		/* return nothing.. */
+		g_free (path);
+		path = NULL;
+	}
+out:
+	return path;
+}
+
+GMainLoop *_loop = NULL;
+
+/**
+ * gpk_dbus_task_install_package_files_ready_callback:
+ **/
+static void
+gpk_dbus_task_install_package_files_ready_callback (GObject *source_object, GAsyncResult *res, GpkDbusTask *task)
+{
+	gboolean ret;
+	GError *error_local = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	ret = g_file_copy_finish (G_FILE (source_object), res, &error_local);
+	if (!ret) {
+		egg_warning ("failed to copy file: %s", error_local->message);
+		g_error_free (error_local);
+	}
+
+	g_main_loop_quit (_loop);
+}
+
+/**
+ * gpk_dbus_task_install_package_files_progress_callback:
+ **/
+static void
+gpk_dbus_task_install_package_files_progress_callback (goffset current_num_bytes, goffset total_num_bytes, GpkDbusTask *task)
+{
+	guint percentage;
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	percentage = (current_num_bytes * 100) / total_num_bytes;
+	gpk_modal_dialog_set_percentage (task->priv->dialog, percentage);
+}
+
+/**
+ * gpk_dbus_task_install_package_files_copy_non_native:
+ *
+ * Copy the new file into a new file that can be read by packagekitd, and
+ * that can't be written into by other users.
+ *
+ * Return value: the new file path, or %NULL for copy error
+ **/
+static gchar *
+gpk_dbus_task_install_package_files_copy_non_native (GpkDbusTask *task, const gchar *filename, GError **error)
+{
+	GFile *file = NULL;
+	GFile *dest = NULL;
+	gchar *basename = NULL;
+	gchar *dest_path = NULL;
+	gchar *new_path = NULL;
+	gchar *cache_path = NULL;
+	GError *error_local = NULL;
+
+	/* create the non FUSE temp directory */
+	cache_path = gpk_dbus_task_install_package_files_get_user_temp (task, "native-cache", &error_local);
+	if (cache_path == NULL) {
+		*error = g_error_new (1, 0, "failed to create temp directory: %s", error_local->message);
+		g_error_free (error_local);
+		goto out;
+	}
+
+	/* get the final location */
+	file = g_file_new_for_path (filename);
+	basename = g_file_get_basename (file);
+	dest_path = g_build_filename (cache_path, basename, NULL);
+
+	/* copy the file */
+	dest = g_file_new_for_path (dest_path);
+	g_file_copy_async (file, dest, G_FILE_COPY_OVERWRITE, 0, NULL,
+			   (GFileProgressCallback) gpk_dbus_task_install_package_files_progress_callback, task,
+			   (GAsyncReadyCallback) gpk_dbus_task_install_package_files_ready_callback, task);
+	_loop = g_main_loop_new (NULL, FALSE);
+	g_main_loop_run (_loop);
+	g_main_loop_unref (_loop);
+
+	/* return the modified file item */
+	new_path = g_strdup (dest_path);
+
+out:
+	if (file != NULL)
+		g_object_unref (file);
+	if (dest != NULL)
+		g_object_unref (dest);
+	g_free (basename);
+	g_free (cache_path);
+	g_free (dest_path);
+	return new_path;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_native_check:
+ *
+ * Allow the user to confirm the package copy to ~/.PackageKit/native-cache
+ * as we cannot access FUSE mounts as the root user.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static gboolean
+gpk_dbus_task_install_package_files_native_check (GpkDbusTask *task, GPtrArray *array, GError **error)
+{
+	guint i;
+	const gchar *data;
+	gchar *cache_path = NULL;
+	gchar *filename;
+	gboolean ret;
+	gboolean native;
+	GPtrArray *array_missing;
+	const gchar *message_part;
+	const gchar *title;
+	gchar *message;
+	GtkResponseType button;
+	GError *error_local = NULL;
+	GFile *file;
+
+	/* check if any files are non-native and need to be copied */
+	array_missing = g_ptr_array_new ();
+	for (i=0; i<array->len; i++) {
+		data = (const gchar *) g_ptr_array_index (array, i);
+		/* if file is non-native, it's on a FUSE mount (probably created by GVFS).
+		 * See https://bugzilla.redhat.com/show_bug.cgi?id=456094 */
+		file = g_file_new_for_path (data);
+		native = g_file_is_native (file);
+		g_object_unref (file);
+		if (!native) {
+			egg_debug ("%s is non-native", data);
+			g_ptr_array_add (array_missing, g_strdup (data));
+		}
+	}
+
+	/* optional */
+	ret = gconf_client_get_bool (task->priv->gconf_client, GPK_CONF_SHOW_COPY_CONFIRM, NULL);
+	if (ret && array_missing->len > 0) {
+		/* TRANSLATORS: title: we have to copy the private files to a public location */
+		title = ngettext ("Do you want to copy this file?",
+				  "Do you want to copy these files?", array_missing->len);
+		/* TRANSLATORS: message: explain to the user what we are doing */
+		message_part = ngettext ("This package file has to be copied from a private directory so it can be installed:",
+					 "Several package files have to be copied from a private directory so they can be installed:",
+					 array_missing->len);
+		message = gpk_dbus_task_ptr_array_to_bullets (array_missing, message_part);
+
+		/* show UI */
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_message (task->priv->dialog, message);
+		gpk_modal_dialog_set_image (task->priv->dialog, "dialog-warning");
+		/* TRANSLATORS: button: copy file from one directory to another */
+		gpk_modal_dialog_set_action (task->priv->dialog, ngettext ("Copy file", "Copy files", array_missing->len));
+		gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-installing-private-files");
+		g_free (message);
+
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		button = gpk_modal_dialog_run (task->priv->dialog);
+		/* did we click no or exit the window? */
+		if (button != GTK_RESPONSE_OK) {
+			*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "Aborted the copy");
+			ret = FALSE;
+			goto out;
+		}
+	}
+
+	/* setup UI */
+	if (array_missing->len > 0) {
+		/* TRANSLATORS: title: we are about to copy files, which may take a few seconds */
+		title = ngettext ("Copying file",
+				  "Copying files", array_missing->len);
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-installing-private-files");
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	}
+
+	/* now we have the okay to copy the files, do so */
+	ret = TRUE;
+	for (i=0; i<array->len; i++) {
+		data = (const gchar *) g_ptr_array_index (array, i);
+
+		/* check we are not on FUSE */
+		file = g_file_new_for_path (data);
+		native = g_file_is_native (file);
+		g_object_unref (file);
+		if (!native) {
+			/* copy the file */
+			filename = gpk_dbus_task_install_package_files_copy_non_native (task, data, &error_local);
+			if (filename == NULL) {
+				*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "failed to copy file %s: %s", data, error_local->message);
+				ret = FALSE;
+				break;
+			}
+
+			/* show progress */
+			gpk_modal_dialog_set_message (task->priv->dialog, filename);
+
+			/* swap data in array */
+			g_free (array->pdata[i]);
+			array->pdata[i] = g_strdup (filename);
+			g_free (filename);
+		}
+	}
+
+	/* did we fail to copy the files */
+	if (!ret) {
+		/* TRANSLATORS: title: tell the user we failed */
+		title = ngettext ("The file could not be copied",
+				  "The files could not be copied", array_missing->len);
+
+		/* show UI */
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_message (task->priv->dialog, error_local->message);
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		gpk_modal_dialog_run (task->priv->dialog);
+		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "files not copied");
+		ret = FALSE;
+		g_error_free (error_local);
+		goto out;
+	}
+out:
+	g_free (cache_path);
+	g_ptr_array_foreach (array_missing, (GFunc) g_free, NULL);
+	g_ptr_array_free (array_missing, TRUE);
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_verify:
+ *
+ * Allow the user to confirm the action
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static gboolean
+gpk_dbus_task_install_package_files_verify (GpkDbusTask *task, GPtrArray *array, GError **error)
+{
+	GtkResponseType button;
+	const gchar *title;
+	gchar *message;
+	gboolean ret = TRUE;
+
+	/* TRANSLATORS: title: confirm the user want's to install a local file */
+	title = ngettext ("Do you want to install this file?",
+			  "Do you want to install these files?", array->len);
+	message = gpk_dbus_task_ptr_array_to_bullets (array, NULL);
+
+	/* show UI */
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_message (task->priv->dialog, message);
+	/* TRANSLATORS: title: installing local files */
+	gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-install-files");
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+	g_free (message);
+
+	/* did we click no or exit the window? */
+	if (button != GTK_RESPONSE_OK) {
+		/* TRANSLATORS: title: the user cancelled the action */
+		title = ngettext ("The file was not installed",
+				  "The files were not installed", array->len);
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		gpk_modal_dialog_run (task->priv->dialog);
+		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "Aborted");
+		ret = FALSE;
+		goto out;
+	}
+out:
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_check_exists:
+ *
+ * Skip files that are not present
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static gboolean
+gpk_dbus_task_install_package_files_check_exists (GpkDbusTask *task, GPtrArray *array, GError **error)
+{
+	guint i;
+	const gchar *data;
+	gboolean ret;
+	GPtrArray *array_missing;
+	const gchar *message_part;
+	const gchar *title;
+	gchar *message;
+
+	array_missing = g_ptr_array_new ();
+
+	/* find missing */
+	for (i=0; i<array->len; i++) {
+		data = (const gchar *) g_ptr_array_index (array, i);
+		ret = g_file_test (data, G_FILE_TEST_EXISTS);
+		if (!ret)
+			g_ptr_array_add (array_missing, g_strdup (data));
+	}
+
+	/* warn, set error and quit */
+	ret = TRUE;
+	if (array_missing->len > 0) {
+		/* TRANSLATORS: title: we couldn't find the file -- very hard to get this */
+		title = ngettext ("File was not found!",
+				  "Files were not found!", array_missing->len);
+
+		/* TRANSLATORS: message: explain what went wrong */
+		message_part = ngettext ("The following file was not found:",
+					 "The following files were not found:", array_missing->len);
+		message = gpk_dbus_task_ptr_array_to_bullets (array_missing, message_part);
+
+		/* show UI */
+		gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+		gpk_modal_dialog_set_title (task->priv->dialog, title);
+		gpk_modal_dialog_set_message (task->priv->dialog, message);
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+		gpk_modal_dialog_run (task->priv->dialog);
+
+		g_free (message);
+
+		ret = FALSE;
+		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "some files did not exist");
+		goto out;
+	}
+
+out:
+	g_ptr_array_foreach (array_missing, (GFunc) g_free, NULL);
+	g_ptr_array_free (array_missing, TRUE);
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_confirm_action:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static gboolean
+gpk_dbus_task_confirm_action (GpkDbusTask *task, const gchar *title, const gchar *message, const gchar *action)
+{
+	GtkResponseType button;
+
+	/* check the user wanted to call this method */
+	if (!task->priv->show_confirm_search)
+		return TRUE;
+
+	/* setup UI */
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_action (task->priv->dialog, action);
+
+	/* set icon */
+	if (task->priv->parent_icon_name != NULL)
+		gpk_modal_dialog_set_image (task->priv->dialog, task->priv->parent_icon_name);
+	else
+		gpk_modal_dialog_set_image (task->priv->dialog, "emblem-system");
+
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_message (task->priv->dialog, message);
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-application-confirm");
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (task->priv->dialog);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_is_installed:
+ **/
+void
+gpk_dbus_task_is_installed (GpkDbusTask *task, const gchar *package_name)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	gchar **package_names = NULL;
+
+	task->priv->role = GPK_DBUS_TASK_ROLE_IS_INSTALLED;
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to reset: %s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* get the package list for the installed packages */
+	package_names = g_strsplit (package_name, "|", 1);
+	egg_warning ("package_name=%s", package_name);
+	ret = pk_client_resolve (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_names, &error_local);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* wait for async reply... */
+out:
+	g_strfreev (package_names);
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_search_file:
+ **/
+void
+gpk_dbus_task_search_file (GpkDbusTask *task, const gchar *search_file)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+
+	task->priv->role = GPK_DBUS_TASK_ROLE_SEARCH_FILE;
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to reset: %s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* get the package list for the installed packages */
+	egg_warning ("package_name=%s", search_file);
+	ret = pk_client_search_file (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), search_file, &error_local);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* wait for async reply... */
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_install_package_files:
+ * @task: a valid #GpkDbusTask instance
+ * @file_rel: a file such as <literal>./hal-devel-0.10.0.rpm</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a file locally, and get the deps from the repositories.
+ * This is useful for double clicking on a .rpm or .deb file.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_package_files (GpkDbusTask *task, gchar **files_rel)
+{
+	GError *error = NULL;
+	gboolean ret;
+	GPtrArray *array;
+//	const gchar *title;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (files_rel != NULL);
+
+	array = pk_strv_to_ptr_array (files_rel);
+
+	/* check the user wanted to call this method */
+	if (task->priv->show_confirm_search) {
+		ret = gpk_dbus_task_install_package_files_verify (task, array, &error);
+		if (!ret) {
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+	}
+
+	/* check all files exist and are readable by the local user */
+	ret = gpk_dbus_task_install_package_files_check_exists (task, array, &error);
+	if (!ret) {
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* check all files exist and are readable by the local user */
+	ret = gpk_dbus_task_install_package_files_native_check (task, array, &error);
+	if (!ret) {
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title: installing a local file */
+	gpk_modal_dialog_set_title (task->priv->dialog, ngettext ("Install local file", "Install local files", array->len));
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+
+	task->priv->files = pk_ptr_array_to_strv (array);
+	gpk_dbus_task_install_package_files_internal (task, TRUE);
+out:
+	g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+	g_ptr_array_free (array, TRUE);
+	if (error != NULL)
+		g_error_free (error);
+}
+
+/**
+ * gpk_dbus_task_install_package_names:
+ * @task: a valid #GpkDbusTask instance
+ * @package: a pakage name such as <literal>hal-info</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a package of the newest and most correct version.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_package_names (GpkDbusTask *task, gchar **packages)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	gchar *message;
+	gchar *text;
+	guint len;
+	guint i;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (packages != NULL);
+
+	task->priv->role = GPK_DBUS_TASK_ROLE_INSTALL_PACKAGE_NAMES;
+
+	/* optional */
+	if (!task->priv->show_confirm_install) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+	len = g_strv_length (packages);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		g_string_append_printf (string, "%s\n", packages[0]);
+	} else {
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "â %s\n", packages[i]);
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n%s",
+				   /* TRANSLATORS: a program needs a package, for instance openoffice-clipart */
+				   ngettext ("An additional package is required:", "Additional packages are required:", len),
+				   text,
+				   /* TRANSLATORS: ask the user if it's okay to search */
+				   ngettext ("Do you want to search for and install this package now?", "Do you want to search for and install these packages now?", len));
+	g_free (text);
+
+	/* make title using application name */
+	if (task->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a package", "%s wants to install packages", len), task->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a package", "A program wants to install packages", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (task, text, message, _("Install"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to search");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title, searching */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Searching for packages"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_WAIT);
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-finding-packages");
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this is an internal error, and should not be seen */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* find out if we can find a package */
+	ret = pk_client_resolve (task->priv->client_primary, PK_FILTER_ENUM_NONE, packages, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+		gpk_dbus_task_error_msg (task, _("Incorrect response from search"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+/*xxx*/
+	/* wait for async reply */
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_install_provide_files:
+ * @task: a valid #GpkDbusTask instance
+ * @full_path: a file path name such as <literal>/usr/sbin/packagekitd</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a package which provides a file on the system.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_provide_files (GpkDbusTask *task, gchar **full_paths)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	guint len;
+	guint i;
+	gchar *text;
+	gchar *message;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (full_paths != NULL);
+
+	task->priv->role = GPK_DBUS_TASK_ROLE_INSTALL_PROVIDE_FILES;
+
+	/* optional */
+	if (!task->priv->show_confirm_search) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+	len = g_strv_length (full_paths);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		g_string_append_printf (string, "%s\n", full_paths[0]);
+	} else {
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "â %s\n", full_paths[i]);
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n\n%s",
+				   /* TRANSLATORS: a program wants to install a file, e.g. /lib/moo.so */
+				   ngettext ("The following file is required:", "The following files are required:", len),
+				   text,
+				   /* TRANSLATORS: confirm with the user */
+				   ngettext ("Do you want to search for this file now?", "Do you want to search for these files now:", len));
+
+	/* make title using application name */
+	if (task->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a file", "%s wants to install files", len), task->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a file", "A program wants to install files", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (task, text, message, _("Install"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to search");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	/* TRANSLATORS: searching for the package that provides the file */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Searching for file"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this is an internal error, and should not be seen */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* do search */
+	ret = pk_client_search_file (task->priv->client_primary, PK_FILTER_ENUM_NONE, full_paths[0], &error_local);
+	if (!ret) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+		gpk_dbus_task_error_msg (task, _("Failed to search for file"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* wait for async reply */
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_install_gstreamer_codec_part:
+ **/
+static PkPackageObj *
+gpk_dbus_task_install_gstreamer_codec_part (GpkDbusTask *task, const gchar *codec_name, const gchar *codec_desc, GError **error)
+{
+	PkPackageList *list = NULL;
+	gboolean ret;
+	PkPackageObj *new_obj = NULL;
+	const PkPackageObj *obj;
+	guint len;
+	gchar *title;
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, error);
+	if (!ret)
+		return NULL;
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* TRANSLATORS: title, searching for codecs */
+	title = g_strdup_printf (_("Searching for plugin: %s"), codec_name);
+	gpk_modal_dialog_set_message (task->priv->dialog, title);
+	g_free (title);
+
+	/* get codec packages, FIXME: synchronous! */
+	pk_client_set_synchronous (task->priv->client_primary, TRUE, NULL);
+	ret = pk_client_what_provides (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED), PK_PROVIDES_ENUM_CODEC, codec_desc, error);
+	pk_client_set_synchronous (task->priv->client_primary, FALSE, NULL);
+	if (!ret)
+		return NULL;
+
+	list = pk_client_get_package_list (task->priv->client_primary);
+	len = pk_package_list_get_size (list);
+
+	/* found nothing? */
+	if (len == 0) {
+		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "failed to find: %s", codec_desc);
+		goto out;
+	}
+
+	/* gstreamer-ffmpeg and gstreamer-plugins-ugly both provide mp3 playback, choose one */
+	if (len > 1)
+		egg_warning ("choosing one of the provides as more than one match");
+
+	/* always use the first one */
+	obj = pk_package_list_get_obj (list, 0);
+	if (obj == NULL)
+		egg_error ("obj cannot be NULL");
+
+	/* copy the object */
+	new_obj = pk_package_obj_copy (obj);
+out:
+	if (list != NULL)
+		g_object_unref (list);
+	return new_obj;
+}
+
+/**
+ * gpk_dbus_task_install_gstreamer_resources_confirm:
+ **/
+static gboolean
+gpk_dbus_task_install_gstreamer_resources_confirm (GpkDbusTask *task, gchar **codec_names)
+{
+	guint i;
+	guint len;
+	gchar *text;
+	gchar *confirm_text;
+	gchar **parts;
+	gboolean ret;
+	GString *string;
+	const gchar *title;
+	const gchar *message;
+
+	len = g_strv_length (codec_names);
+	/* TRANSLATORS: title: we need a codec */
+	title = ngettext ("An additional plugin is required to play this content", "Additional plugins are required to play this content", len);
+	/* TRANSLATORS: we are listing the plugins in a box */
+	message = ngettext ("The following plugin is required:", "The following plugins are required:", len);
+
+	string = g_string_new ("");
+	g_string_append_printf (string, "%s\n%s\n\n", title, message);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		parts = g_strsplit (codec_names[0], "|", 2);
+		g_string_append_printf (string, "%s\n", parts[0]);
+		g_strfreev (parts);
+	} else {
+		for (i=0; i<len; i++) {
+			parts = g_strsplit (codec_names[i], "|", 2);
+			g_string_append_printf (string, "â %s\n", parts[0]);
+			g_strfreev (parts);
+		}
+	}
+
+	/* TRANSLATORS: ask for confirmation */
+	message = ngettext ("Do you want to search for this now?", "Do you want to search for these now?", len);
+	g_string_append_printf (string, "\n%s\n", message);
+
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* make title using application name */
+	if (task->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		confirm_text = g_strdup_printf (ngettext ("%s requires an additional plugin", "%s requires additional plugins", len), task->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		confirm_text = g_strdup (ngettext ("A program requires an additional plugin", "A program requires additional plugins", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (task, confirm_text, text, _("Search"));
+	g_free (confirm_text);
+	g_free (text);
+
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_install_gstreamer_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @codecs: a codec_type such as <literal>application/text</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a mime type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_gstreamer_resources (GpkDbusTask *task, gchar **codec_names)
+{
+	gboolean ret = TRUE;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	guint i;
+	guint len;
+	PkPackageObj *obj_new;
+	gchar **parts;
+	GtkResponseType button;
+	gchar *info_url;
+	PkPackageList *list = NULL;
+	const gchar *title;
+	const gchar *message;
+
+	/* check it's not session wide banned in gconf */
+	ret = gconf_client_get_bool (task->priv->gconf_client, GPK_CONF_ENABLE_CODEC_HELPER, NULL);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FORBIDDEN, "not enabled in GConf : %s", GPK_CONF_ENABLE_CODEC_HELPER);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_search) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* confirm */
+	ret = gpk_dbus_task_install_gstreamer_resources_confirm (task, codec_names);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to search");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: search for codec */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Searching for plugins"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_WAIT);
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-finding-packages");
+
+	/* setup the UI */
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* save the objects to download in a list */
+	list = pk_package_list_new ();
+
+	len = g_strv_length (codec_names);
+	for (i=0; i<len; i++) {
+		parts = g_strsplit (codec_names[i], "|", 2);
+		if (g_strv_length (parts) != 2) {
+			egg_warning ("invalid line '%s', expecting a | delimiter", codec_names[i]);
+			continue;
+		}
+		obj_new = gpk_dbus_task_install_gstreamer_codec_part (task, parts[0], parts[1], &error_local);
+		if (obj_new == NULL) {
+			if (task->priv->show_warning) {
+				info_url = gpk_vendor_get_not_found_url (task->priv->vendor, GPK_VENDOR_URL_TYPE_CODEC);
+				/* only show the "more info" button if there is a valid link */
+				if (info_url != NULL)
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+				else
+					gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+				/* TRANSLATORS: failed to search for codec */
+				gpk_modal_dialog_set_title (task->priv->dialog, _("Failed to search for plugin"));
+				/* TRANSLATORS: no software sources have the wanted codec */
+				gpk_modal_dialog_set_message (task->priv->dialog, _("Could not find plugin in any configured software source"));
+				gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-package-not-found");
+
+				/* TRANSLATORS: button text */
+				gpk_modal_dialog_set_action (task->priv->dialog, _("More information"));
+				gpk_modal_dialog_present (task->priv->dialog);
+				button = gpk_modal_dialog_run (task->priv->dialog);
+				if (button == GTK_RESPONSE_OK)
+					gpk_gnome_open (info_url);
+				g_free (info_url);
+			}
+			error = g_error_new (GPK_DBUS_ERROR, error_local->code, "%s", error_local->message);
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+		pk_obj_list_add (PK_OBJ_LIST(list), obj_new);
+		pk_package_obj_free (obj_new);
+		g_strfreev (parts);
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_deps) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	title = ngettext ("Install the following plugin", "Install the following plugins", len);
+	message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", len);
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (task->priv->dialog, list);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_message (task->priv->dialog, message);
+	gpk_modal_dialog_set_image (task->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install codecs */
+	gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (task->priv->dialog);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to download");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks2:
+	/* install with deps */
+	task->priv->package_ids = pk_package_list_to_strv (list);
+	gpk_dbus_task_install_package_ids_dep_check (task);
+out:
+	if (list != NULL)
+		g_object_unref (list);
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_install_mime_types:
+ * @task: a valid #GpkDbusTask instance
+ * @mime_type: a mime_type such as <literal>application/text</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a mime type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_mime_types (GpkDbusTask *task, gchar **mime_types)
+{
+	gboolean ret;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	guint len;
+	gchar *message;
+	gchar *text;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (mime_types != NULL);
+
+	task->priv->role = GPK_DBUS_TASK_ROLE_INSTALL_MIME_TYPES;
+
+	/* check it's not session wide banned in gconf */
+	ret = gconf_client_get_bool (task->priv->gconf_client, GPK_CONF_ENABLE_MIME_TYPE_HELPER, NULL);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FORBIDDEN, "not enabled in GConf : %s", GPK_CONF_ENABLE_MIME_TYPE_HELPER);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_search) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* make sure the user wants to do action */
+	message = g_strdup_printf ("%s\n\n%s\n\n%s",
+				    /* TRANSLATORS: message: mime type opener required */
+				   _("An additional program is required to open this type of file:"),
+				   mime_types[0],
+				   /* TRANSLATORS: message: confirm with the user */
+				   _("Do you want to search for a program to open this file type now?"));
+
+	/* hardcode for now as we only support one mime type at a time */
+	len = 1;
+
+	/* make title using application name */
+	if (task->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s requires a new mime type", "%s requires new mime types", len), task->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program requires a new mime type", "A program requires new mime types", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (task, text, message, _("Search"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to search");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title: searching for mime type handlers */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Searching for file handlers"));
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_WAIT);
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-finding-packages");
+
+	/* setup the UI */
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* reset */
+	ret = pk_client_reset (task->priv->client_primary, &error_local);
+	if (!ret) {
+		/* TRANSLATORS: this is an internal error, and should not be seen */
+		gpk_dbus_task_error_msg (task, _("Failed to reset client"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* action */
+	ret = pk_client_what_provides (task->priv->client_primary, 0,//pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED),
+				       PK_PROVIDES_ENUM_MIMETYPE, mime_types[0], &error_local);
+	if (!ret) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+		gpk_dbus_task_error_msg (task, _("Failed to search for provides"), error_local);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* wait for async reply */
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+}
+
+/**
+ * gpk_dbus_task_font_tag_to_lang:
+ **/
+static gchar *
+gpk_dbus_task_font_tag_to_lang (const gchar *tag)
+{
+	gchar *lang = NULL;
+#if 0
+	*** We do not yet enable this code due to a few bugs in fontconfig ***
+	http://bugs.freedesktop.org/show_bug.cgi?id=18846 and
+	http://bugs.freedesktop.org/show_bug.cgi?id=18847
+
+	FcPattern *pat = NULL;
+	FcChar8 *fclang;
+	FcResult res;
+
+	/* parse the tag */
+	pat = FcNameParse ((FcChar8 *) tag);
+	if (pat == NULL) {
+		egg_warning ("cannot parse: '%s'", tag);
+		goto out;
+	}
+	FcPatternPrint (pat);
+	res = FcPatternGetString (pat, FC_LANG, 0, &fclang);
+	if (res != FcResultMatch) {
+		egg_warning ("failed to get string for: '%s': %i", tag, res);
+		goto out;
+	}
+	lang = g_strdup ((gchar *) fclang);
+out:
+	if (pat != NULL)
+		FcPatternDestroy (pat);
+#else
+	guint len;
+
+	/* verify we have enough to remove prefix */
+	len = strlen (tag);
+	if (len < 7)
+		goto out;
+	/* this is a bodge */
+	lang = g_strdup (&tag[6]);
+out:
+#endif
+	return lang;
+}
+
+
+/**
+ * gpk_dbus_task_font_tag_to_localised_name:
+ **/
+static gchar *
+gpk_dbus_task_font_tag_to_localised_name (GpkDbusTask *task, const gchar *tag)
+{
+	gchar *lang;
+	gchar *language = NULL;
+	gchar *name;
+
+	/* use fontconfig to get the language code */
+	lang = gpk_dbus_task_font_tag_to_lang (tag);
+	if (lang == NULL) {
+		/* TRANSLATORS: we could not parse the ISO639 code from the fontconfig tag name */
+		name = g_strdup_printf ("%s: %s", _("Language tag not parsed"), tag);
+		goto out;
+	}
+
+	/* convert to localisable name */
+	language = gpk_language_iso639_to_language (task->priv->language, lang);
+	if (language == NULL) {
+		/* TRANSLATORS: we could not find en_US string for ISO639 code */
+		name = g_strdup_printf ("%s: %s", _("Language code not matched"), lang);
+		goto out;
+	}
+
+	/* get translation, or return untranslated string */
+	name = g_strdup (dgettext("iso_639", language));
+	if (name == NULL)
+		name = g_strdup (language);
+out:
+	g_free (lang);
+	g_free (language);
+	return name;
+}
+
+/**
+ * gpk_dbus_task_install_fontconfig_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @fonts: font description such as <literal>lang:fr</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a mime type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *task, gchar **fonts)
+{
+	gboolean ret;
+	PkPackageList *list = NULL;
+	PkPackageList *list_tmp = NULL;
+	GtkResponseType button;
+	gchar *info_url;
+	GError *error = NULL;
+	GError *error_local = NULL;
+	guint i;
+	guint len;
+	gchar *text;
+	gchar *message;
+	const gchar *title;
+	const gchar *title_part;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+	g_return_if_fail (fonts != NULL);
+
+	/* get number of fonts to install */
+	len = g_strv_length (fonts);
+
+	/* check it's not session wide banned in gconf */
+	ret = gconf_client_get_bool (task->priv->gconf_client, GPK_CONF_ENABLE_FONT_HELPER, NULL);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FORBIDDEN, "not enabled in GConf : %s", GPK_CONF_ENABLE_FONT_HELPER);
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_search) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		text = gpk_dbus_task_font_tag_to_localised_name (task, fonts[0]);
+		g_string_append_printf (string, "%s\n", text);
+		g_free (text);
+	} else {
+		for (i=0; i<len; i++) {
+			text = gpk_dbus_task_font_tag_to_localised_name (task, fonts[i]);
+			g_string_append_printf (string, "â %s\n", text);
+			g_free (text);
+		}
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* TRANSLATORS: we need to download a new font package to display a document */
+	title = ngettext ("An additional font is required to view this document correctly.",
+			  "Additional fonts are required to view this document correctly.", len);
+
+	/* TRANSLATORS: we need to download a new font package to display a document */
+	title_part = ngettext ("Do you want to search for a suitable package now?",
+			       "Do you want to search for suitable packages now?", len);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n%s", title, text, title_part);
+	g_free (text);
+
+	/* make title using application name */
+	if (task->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a font", "%s wants to install fonts", len), task->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a font", "A program wants to install fonts", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (task, text, message, _("Search"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to search");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	/* TRANSLATORS: title to show when searching for font files */
+	title = ngettext ("Searching for font", "Searching for fonts", len);
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_image_status (task->priv->dialog, PK_STATUS_ENUM_WAIT);
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-finding-packages");
+
+	/* setup the UI */
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* do each one */
+	list = pk_package_list_new ();
+	for (i=0; i<len; i++) {
+
+		/* reset */
+		ret = pk_client_reset (task->priv->client_primary, &error_local);
+		if (!ret) {
+			/* TRANSLATORS: this is an internal error, and should not be seen */
+			gpk_dbus_task_error_msg (task, _("Failed to reset client"), error_local);
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* set timeout */
+		pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+		/* action: FIXME: synchronous */
+		pk_client_set_synchronous (task->priv->client_primary, TRUE, NULL);
+		ret = pk_client_what_provides (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED),
+					       PK_PROVIDES_ENUM_FONT, fonts[i], &error_local);
+		pk_client_set_synchronous (task->priv->client_primary, FALSE, NULL);
+		if (!ret) {
+			/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+			gpk_dbus_task_error_msg (task, _("Failed to search for provides"), error_local);
+			error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "%s", error_local->message);
+			dbus_g_method_return_error (task->priv->context, error);
+			goto out;
+		}
+
+		/* add to main list */
+		list_tmp = pk_client_get_package_list (task->priv->client_primary);
+		pk_obj_list_add_list (PK_OBJ_LIST (list), PK_OBJ_LIST (list_tmp));
+		g_object_unref (list_tmp);
+	}
+
+	/* found nothing? */
+	len = pk_package_list_get_size (list);
+	if (len == 0) {
+		if (task->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (task->priv->vendor, GPK_VENDOR_URL_TYPE_FONT);
+			/* TRANSLATORS: title: cannot find in sources */
+			title = ngettext ("Failed to find font", "Failed to find fonts", len);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			gpk_modal_dialog_set_title (task->priv->dialog, title);
+			/* TRANSLATORS: message: tell the user we suck */
+			gpk_modal_dialog_set_message (task->priv->dialog, _("No new fonts can be found for this document"));
+			gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-package-not-found");
+			/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+			gpk_modal_dialog_set_action (task->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (task->priv->dialog);
+			button = gpk_modal_dialog_run (task->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "failed to find font");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_deps) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	/* TRANSLATORS: title: show a list of fonts */
+	title = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", len);
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (task->priv->dialog, list);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_message (task->priv->dialog, title);
+	gpk_modal_dialog_set_image (task->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install a font */
+	gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (task->priv->dialog);
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to download");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks2:
+	/* convert to list of package id's */
+	task->priv->package_ids = pk_package_list_to_strv (list);
+	gpk_dbus_task_install_package_ids_dep_check (task);
+
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (error_local != NULL)
+		g_error_free (error_local);
+	if (list != NULL)
+		g_object_unref (list);
+}
+
+/**
+ * gpk_dbus_task_catalog_progress_cb:
+ **/
+static void
+gpk_dbus_task_catalog_progress_cb (PkCatalog *catalog, PkCatalogProgress mode, const gchar *text, GpkDbusTask *task)
+{
+	gchar *message = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (task));
+
+	if (mode == PK_CATALOG_PROGRESS_PACKAGES) {
+		/* TRANSLATORS: finding the package names for a catalog */
+		message = g_strdup_printf (_("Finding package name: %s"), text);
+	} else if (mode == PK_CATALOG_PROGRESS_FILES) {
+		/* TRANSLATORS: finding a package for a file for a catalog */
+		message = g_strdup_printf (_("Finding file name: %s"), text);
+	} else if (mode == PK_CATALOG_PROGRESS_PROVIDES) {
+		/* TRANSLATORS: finding a package which can provide a virtual provide */
+		message = g_strdup_printf (_("Finding a package to provide: %s"), text);
+	}
+	gpk_dbus_task_set_status (task, PK_STATUS_ENUM_QUERY);
+	gpk_modal_dialog_set_message (task->priv->dialog, message);
+	g_free (message);
+}
+
+/**
+ * gpk_dbus_task_install_catalogs:
+ **/
+void
+gpk_dbus_task_install_catalogs (GpkDbusTask *task, gchar **filenames)
+{
+	GError *error = NULL;
+	GtkResponseType button;
+	gchar *message;
+	const gchar *title;
+	const PkPackageObj *obj;
+	PkPackageList *list = NULL;
+	PkCatalog *catalog;
+	GString *string;
+	gchar *text;
+	guint len;
+	guint i;
+
+	len = g_strv_length (filenames);
+
+	/* optional */
+	if (!task->priv->show_confirm_search) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* TRANSLATORS: title to install package catalogs */
+	title = ngettext ("Do you want to install this catalog?",
+			  "Do you want to install these catalogs?", len);
+	message = g_strjoinv ("\n", filenames);
+
+	/* show UI */
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_title (task->priv->dialog, title);
+	gpk_modal_dialog_set_message (task->priv->dialog, message);
+	/* TRANSLATORS: button: install catalog */
+	gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+	gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-install-catalogs");
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+	g_free (message);
+
+	/* did we click no or exit the window? */
+	if (button != GTK_RESPONSE_OK) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "did not agree to install");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title: install package catalogs, that is, instructions for installing */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Install catalogs"));
+	gpk_dbus_task_set_status (task, PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (task->priv->show_progress)
+		gpk_modal_dialog_present (task->priv->dialog);
+
+	/* get files to be installed */
+	catalog = pk_catalog_new ();
+	g_signal_connect (catalog, "progress", G_CALLBACK (gpk_dbus_task_catalog_progress_cb), task);
+	list = pk_catalog_process_files (catalog, filenames);
+	g_object_unref (catalog);
+
+	/* nothing to do? */
+	len = pk_package_list_get_size (list);
+	if (len == 0) {
+		/* show UI */
+		if (task->priv->show_warning) {
+			/* TRANSLATORS: title: we've already got all these packages installed */
+			gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			gpk_modal_dialog_set_title (task->priv->dialog, _("No packages need to be installed"));
+			gpk_modal_dialog_set_help_id (task->priv->dialog, "dialog-catalog-none-required");
+			gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+			gpk_modal_dialog_run (task->priv->dialog);
+		}
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_FAILED, "No packages need to be installed");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+	/* optional */
+	if (!task->priv->show_confirm_deps) {
+		egg_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	/* TRANSLATORS: display a list of packages to install */
+	string = g_string_new (_("The following packages are marked to be installed from the catalog:"));
+	g_string_append (string, "\n\n");
+
+	/* process package list */
+	for (i=0; i<len; i++) {
+		obj = pk_package_list_get_obj (list, i);
+		text = gpk_package_id_format_oneline (obj->id, obj->summary);
+		g_string_append_printf (string, "%s\n", text);
+		g_free (text);
+	}
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	gpk_modal_dialog_setup (task->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	/* TRANSLATORS: title: allow user to confirm */
+	gpk_modal_dialog_set_title (task->priv->dialog, _("Install packages in catalog?"));
+	gpk_modal_dialog_set_message (task->priv->dialog, text);
+	gpk_modal_dialog_set_image (task->priv->dialog, "dialog-question");
+	/* TRANSLATORS: button: install packages in catalog */
+	gpk_modal_dialog_set_action (task->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (task->priv->dialog, task->priv->timestamp);
+	button = gpk_modal_dialog_run (task->priv->dialog);
+
+	g_free (text);
+
+	/* did we click no or exit the window? */
+	if (button != GTK_RESPONSE_OK) {
+		error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_CANCELLED, "Action was cancelled");
+		dbus_g_method_return_error (task->priv->context, error);
+		goto out;
+	}
+
+skip_checks2:
+	/* convert to list of package id's */
+	task->priv->package_ids = pk_package_list_to_strv (list);
+	gpk_dbus_task_install_package_ids_dep_check (task);
+
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (list != NULL)
+		g_object_unref (list);
+}
+
+/**
+ * gpk_dbus_task_get_package_for_exec:
+ **/
+static gchar *
+gpk_dbus_task_get_package_for_exec (GpkDbusTask *task, const gchar *exec)
+{
+	gchar *package = NULL;
+	gboolean ret;
+	GError *error = NULL;
+	guint length;
+	PkPackageList *list = NULL;
+	const PkPackageObj *obj;
+
+	/* reset dbus_task */
+	ret = pk_client_reset (task->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* set timeout */
+	pk_client_set_timeout (task->priv->client_primary, task->priv->timeout, NULL);
+
+	/* find the package name */
+	pk_client_set_synchronous (task->priv->client_primary, TRUE, NULL);
+	ret = pk_client_search_file (task->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), exec, &error);
+	pk_client_set_synchronous (task->priv->client_primary, FALSE, NULL);
+	if (!ret) {
+		egg_warning ("failed to search file: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get the list of packages */
+	list = pk_client_get_package_list (task->priv->client_primary);
+	length = pk_package_list_get_size (list);
+
+	/* nothing found */
+	if (length == 0) {
+		egg_debug ("cannot find installed package that provides : %s", exec);
+		goto out;
+	}
+
+	/* check we have one */
+	if (length != 1)
+		egg_warning ("not one return, using first");
+
+	/* copy name */
+	obj = pk_package_list_get_obj (list, 0);
+	package = g_strdup (obj->id->name);
+	egg_debug ("got package %s", package);
+
+out:
+	/* use the exec name if we can't find an installed package */
+	if (list != NULL)
+		g_object_unref (list);
+	return package;
+}
+
+/**
+ * gpk_dbus_task_path_is_trusted:
+ **/
+static gboolean
+gpk_dbus_task_path_is_trusted (const gchar *exec)
+{
+	/* special case the plugin helper -- it's trusted */
+	if (egg_strequal (exec, "/usr/libexec/gst-install-plugins-helper") ||
+	    egg_strequal (exec, "/usr/libexec/pk-gstreamer-install"))
+		return TRUE;
+	return FALSE;
+}
+
+/**
+ * gpk_dbus_task_set_exec:
+ *
+ * This sets the package name of the application that is trying to install
+ * software, e.g. "totem" and is used for the PkDesktop lookup to provide
+ * a translated name and icon.
+ **/
+gboolean
+gpk_dbus_task_set_exec (GpkDbusTask *task, const gchar *exec)
+{
+	GpkX11 *x11;
+	gchar *package = NULL;
+
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (task), FALSE);
+
+	/* old values invalid */
+	g_free (task->priv->parent_title);
+	g_free (task->priv->parent_icon_name);
+	task->priv->parent_title = NULL;
+	task->priv->parent_icon_name = NULL;
+
+	/* is the binary trusted, i.e. can we probe it's window properties */
+	if (gpk_dbus_task_path_is_trusted (exec)) {
+		egg_debug ("using application window properties");
+		/* get from window properties */
+		x11 = gpk_x11_new ();
+		gpk_x11_set_window (x11, task->priv->parent_window);
+		task->priv->parent_title = gpk_x11_get_title (x11);
+		g_object_unref (x11);
+		goto out;
+	}
+
+	/* get from installed database */
+	package = gpk_dbus_task_get_package_for_exec (task, exec);
+	egg_debug ("got package %s", package);
+
+	/* try to get from PkDesktop */
+	if (package != NULL) {
+		task->priv->parent_title = gpk_desktop_guess_localised_name (task->priv->desktop, package);
+		task->priv->parent_icon_name = gpk_desktop_guess_icon_name (task->priv->desktop, package);
+		/* fallback to package name */
+		if (task->priv->parent_title == NULL) {
+			egg_debug ("did not get localised description for %s", package);
+			task->priv->parent_title = g_strdup (package);
+		}
+	}
+
+	/* fallback to exec - eugh... */
+	if (task->priv->parent_title == NULL) {
+		egg_debug ("did not get package for %s, using exec basename", package);
+		task->priv->parent_title = g_path_get_basename (exec);
+	}
+out:
+	g_free (package);
+	egg_debug ("got name=%s, icon=%s", task->priv->parent_title, task->priv->parent_icon_name);
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_class_init:
+ * @klass: The #GpkDbusTaskClass
+ **/
+static void
+gpk_dbus_task_class_init (GpkDbusTaskClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_dbus_task_finalize;
+	g_type_class_add_private (klass, sizeof (GpkDbusTaskPrivate));
+}
+
+/**
+ * gpk_dbus_task_init:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static void
+gpk_dbus_task_init (GpkDbusTask *task)
+{
+	gboolean ret;
+	GtkWindow *main_window;
+
+	task->priv = GPK_DBUS_TASK_GET_PRIVATE (task);
+
+	task->priv->package_ids = NULL;
+	task->priv->files = NULL;
+	task->priv->parent_window = NULL;
+	task->priv->parent_title = NULL;
+	task->priv->parent_icon_name = NULL;
+	task->priv->error_details = NULL;
+	task->priv->context = NULL;
+	task->priv->exit = PK_EXIT_ENUM_FAILED;
+	task->priv->show_confirm_search = TRUE;
+	task->priv->show_confirm_deps = TRUE;
+	task->priv->show_confirm_install = TRUE;
+	task->priv->show_progress = TRUE;
+	task->priv->show_finished = TRUE;
+	task->priv->show_warning = TRUE;
+	task->priv->timestamp = 0;
+	task->priv->timeout = -1;
+	task->priv->last_exit_code = PK_ERROR_ENUM_UNKNOWN;
+	task->priv->role = GPK_DBUS_TASK_ROLE_UNKNOWN;
+
+	/* add application specific icons to search path */
+	gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
+					   GPK_DATA G_DIR_SEPARATOR_S "icons");
+
+	/* only initialise if the application didn't do it before */
+	if (!notify_is_initted ())
+		notify_init ("gpk-dbus_task");
+
+	task->priv->vendor = gpk_vendor_new ();
+	task->priv->dialog = gpk_modal_dialog_new ();
+	main_window = gpk_modal_dialog_get_window (task->priv->dialog);
+	gpk_modal_dialog_set_window_icon (task->priv->dialog, "pk-package-installed");
+	g_signal_connect (task->priv->dialog, "cancel",
+			  G_CALLBACK (gpk_dbus_task_button_cancel_cb), task);
+	g_signal_connect (task->priv->dialog, "close",
+			  G_CALLBACK (gpk_dbus_task_button_close_cb), task);
+
+	/* helpers */
+	task->priv->helper_repo_signature = gpk_helper_repo_signature_new ();
+	g_signal_connect (task->priv->helper_repo_signature, "event", G_CALLBACK (gpk_dbus_task_repo_signature_event_cb), task);
+	gpk_helper_repo_signature_set_parent (task->priv->helper_repo_signature, main_window);
+
+	task->priv->helper_eula = gpk_helper_eula_new ();
+	g_signal_connect (task->priv->helper_eula, "event", G_CALLBACK (gpk_dbus_task_eula_event_cb), task);
+	gpk_helper_eula_set_parent (task->priv->helper_eula, main_window);
+
+	task->priv->helper_run = gpk_helper_run_new ();
+	gpk_helper_run_set_parent (task->priv->helper_run, main_window);
+
+	task->priv->helper_untrusted = gpk_helper_untrusted_new ();
+	g_signal_connect (task->priv->helper_untrusted, "event", G_CALLBACK (gpk_dbus_task_untrusted_event_cb), task);
+	gpk_helper_untrusted_set_parent (task->priv->helper_untrusted, main_window);
+
+	task->priv->helper_chooser = gpk_helper_chooser_new ();
+	g_signal_connect (task->priv->helper_chooser, "event", G_CALLBACK (gpk_dbus_task_chooser_event_cb), task);
+	gpk_helper_chooser_set_parent (task->priv->helper_chooser, main_window);
+
+	/* map ISO639 to language names */
+	task->priv->language = gpk_language_new ();
+	gpk_language_populate (task->priv->language, NULL);
+
+	/* use gconf for session settings */
+	task->priv->gconf_client = gconf_client_get_default ();
+
+	/* get actions */
+	task->priv->control = pk_control_new ();
+	task->priv->roles = pk_control_get_actions (task->priv->control, NULL);
+
+	task->priv->client_primary = pk_client_new ();
+	pk_client_set_use_buffer (task->priv->client_primary, TRUE, NULL);
+	g_signal_connect (task->priv->client_primary, "finished",
+			  G_CALLBACK (gpk_dbus_task_finished_cb), task);
+	g_signal_connect (task->priv->client_primary, "progress-changed",
+			  G_CALLBACK (gpk_dbus_task_progress_changed_cb), task);
+	g_signal_connect (task->priv->client_primary, "status-changed",
+			  G_CALLBACK (gpk_dbus_task_status_changed_cb), task);
+	g_signal_connect (task->priv->client_primary, "error-code",
+			  G_CALLBACK (gpk_dbus_task_error_code_cb), task);
+	g_signal_connect (task->priv->client_primary, "package",
+			  G_CALLBACK (gpk_dbus_task_package_cb), task);
+	g_signal_connect (task->priv->client_primary, "allow-cancel",
+			  G_CALLBACK (gpk_dbus_task_allow_cancel_cb), task);
+	g_signal_connect (task->priv->client_primary, "repo-signature-required",
+			  G_CALLBACK (gpk_dbus_task_repo_signature_required_cb), task);
+	g_signal_connect (task->priv->client_primary, "eula-required",
+			  G_CALLBACK (gpk_dbus_task_eula_required_cb), task);
+
+	/* this is asynchronous, else we get into livelock */
+	task->priv->client_secondary = pk_client_new ();
+	g_signal_connect (task->priv->client_secondary, "finished",
+			  G_CALLBACK (gpk_dbus_task_finished_cb), task);
+	g_signal_connect (task->priv->client_secondary, "error-code",
+			  G_CALLBACK (gpk_dbus_task_error_code_cb), task);
+	g_signal_connect (task->priv->client_secondary, "status-changed",
+			  G_CALLBACK (gpk_dbus_task_status_changed_cb), task);
+
+	/* used for icons and translations */
+	task->priv->desktop = pk_desktop_new ();
+	ret = pk_desktop_open_database (task->priv->desktop, NULL);
+	if (!ret)
+		egg_warning ("failed to open desktop database");
+}
+
+/**
+ * gpk_dbus_task_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_dbus_task_finalize (GObject *object)
+{
+	GpkDbusTask *task;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (object));
+
+	task = GPK_DBUS_TASK (object);
+	g_return_if_fail (task->priv != NULL);
+
+	g_free (task->priv->parent_title);
+	g_free (task->priv->parent_icon_name);
+	g_free (task->priv->error_details);
+	g_strfreev (task->priv->files);
+	g_strfreev (task->priv->package_ids);
+	g_object_unref (task->priv->client_primary);
+	g_object_unref (task->priv->client_secondary);
+	g_object_unref (task->priv->control);
+	g_object_unref (task->priv->desktop);
+	g_object_unref (task->priv->gconf_client);
+	g_object_unref (task->priv->dialog);
+	g_object_unref (task->priv->vendor);
+	g_object_unref (task->priv->language);
+	g_object_unref (task->priv->helper_eula);
+	g_object_unref (task->priv->helper_run);
+	g_object_unref (task->priv->helper_untrusted);
+	g_object_unref (task->priv->helper_chooser);
+	g_object_unref (task->priv->helper_repo_signature);
+
+	G_OBJECT_CLASS (gpk_dbus_task_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_dbus_task_new:
+ *
+ * PkClient is a nice GObject wrapper for gnome-packagekit and makes installing software easy
+ *
+ * Return value: A new %GpkDbusTask instance
+ **/
+GpkDbusTask *
+gpk_dbus_task_new (void)
+{
+	GpkDbusTask *task;
+	task = g_object_new (GPK_TYPE_DBUS_TASK, NULL);
+	return GPK_DBUS_TASK (task);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+gpk_dbus_task_test (gpointer data)
+{
+	EggTest *test = (EggTest *) data;
+	GpkDbusTask *task;
+	gchar *lang;
+	gchar *language;
+	gchar *package;
+	gboolean ret;
+#if 0
+	const gchar *fonts[] = { ":lang=mn", NULL };
+	GError *error;
+#endif
+
+	if (egg_test_start (test, "GpkChooser") == FALSE)
+		return;
+
+	/************************************************************/
+	egg_test_title (test, "get GpkDbusTask object");
+	task = gpk_dbus_task_new ();
+	if (task != NULL)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, NULL);
+
+	/************************************************************/
+	egg_test_title (test, "convert tag to lang");
+	lang = gpk_dbus_task_font_tag_to_lang (":lang=mn");
+	if (egg_strequal (lang, "mn"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "lang '%s'", lang);
+	g_free (lang);
+
+	/************************************************************/
+	egg_test_title (test, "convert tag to language");
+	language = gpk_dbus_task_font_tag_to_localised_name (task, ":lang=mn");
+	if (egg_strequal (language, "Mongolian"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "language '%s'", language);
+	g_free (language);
+
+	/************************************************************/
+	egg_test_title (test, "test trusted path");
+	ret = gpk_dbus_task_path_is_trusted ("/usr/libexec/gst-install-plugins-helper");
+	if (ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed to identify trusted");
+
+	/************************************************************/
+	egg_test_title (test, "test trusted path");
+	ret = gpk_dbus_task_path_is_trusted ("/usr/bin/totem");
+	if (!ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "identify untrusted as trusted!");
+
+	/************************************************************/
+	egg_test_title (test, "get package for exec");
+	package = gpk_dbus_task_get_package_for_exec (task, "/usr/bin/totem");
+	if (egg_strequal (package, "totem"))
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "package '%s'", package);
+	g_free (package);
+
+	/************************************************************/
+	egg_test_title (test, "set exec");
+	ret = gpk_dbus_task_set_exec (task, "/usr/bin/totem");
+	if (ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed to set exec");
+
+#if 0
+	/************************************************************/
+	egg_test_title (test, "install fonts (no UI)");
+	error = NULL;
+	gpk_dbus_task_set_interaction (task, GPK_CLIENT_INTERACT_NEVER);
+	ret = gpk_dbus_task_install_fontconfig_resources (task, (gchar**)fonts, &error);
+	if (ret)
+		egg_test_success (test, NULL);
+	else {
+		/* success until we can do the server parts */
+		egg_test_success (test, "failed to install font : %s", error->message);
+		g_error_free (error);
+	}
+
+	/************************************************************/
+	egg_test_title (test, "install fonts (if found)");
+	error = NULL;
+	gpk_dbus_task_set_interaction (task, pk_bitfield_from_enums (GPK_CLIENT_INTERACT_CONFIRM_SEARCH, GPK_CLIENT_INTERACT_FINISHED, -1));
+	ret = gpk_dbus_task_install_fontconfig_resources (task, (gchar**)fonts, &error);
+	if (ret)
+		egg_test_success (test, NULL);
+	else {
+		/* success until we can do the server parts */
+		egg_test_success (test, "failed to install font : %s", error->message);
+		g_error_free (error);
+	}
+
+	/************************************************************/
+	egg_test_title (test, "install fonts (always)");
+	error = NULL;
+	gpk_dbus_task_set_interaction (task, GPK_CLIENT_INTERACT_ALWAYS);
+	ret = gpk_dbus_task_install_fontconfig_resources (task, (gchar**)fonts, &error);
+	if (ret)
+		egg_test_success (test, NULL);
+	else {
+		/* success until we can do the server parts */
+		egg_test_success (test, "failed to install font : %s", error->message);
+		g_error_free (error);
+	}
+#endif
+
+	egg_test_end (test);
+}
+#endif
+

Added: trunk/src/gpk-dbus-task.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-dbus-task.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_DBUS_TASK_H
+#define __GPK_DBUS_TASK_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_DBUS_TASK		(gpk_dbus_task_get_type ())
+#define GPK_DBUS_TASK(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_DBUS_TASK, GpkDbusTask))
+#define GPK_DBUS_TASK_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass))
+#define GPK_IS_DBUS_TASK(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_DBUS_TASK))
+#define GPK_IS_DBUS_TASK_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_DBUS_TASK))
+#define GPK_DBUS_TASK_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass))
+
+typedef struct _GpkDbusTaskPrivate	 GpkDbusTaskPrivate;
+typedef struct _GpkDbusTask		 GpkDbusTask;
+typedef struct _GpkDbusTaskClass	 GpkDbusTaskClass;
+
+struct _GpkDbusTask
+{
+	GObject				 parent;
+	GpkDbusTaskPrivate		*priv;
+};
+
+struct _GpkDbusTaskClass
+{
+	GObjectClass	parent_class;
+};
+
+/**
+ * GpkDbusTaskInteract:
+ */
+typedef enum
+{
+	GPK_CLIENT_INTERACT_CONFIRM_SEARCH,
+	GPK_CLIENT_INTERACT_CONFIRM_DEPS,
+	GPK_CLIENT_INTERACT_CONFIRM_INSTALL,
+	GPK_CLIENT_INTERACT_PROGRESS,
+	GPK_CLIENT_INTERACT_FINISHED,
+	GPK_CLIENT_INTERACT_WARNING,
+	GPK_CLIENT_INTERACT_UNKNOWN
+} GpkDbusTaskInteract;
+
+#define GPK_CLIENT_INTERACT_NEVER			0
+#define GPK_CLIENT_INTERACT_ALWAYS			pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \
+										GPK_CLIENT_INTERACT_CONFIRM_DEPS, \
+										GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \
+										GPK_CLIENT_INTERACT_PROGRESS, \
+										GPK_CLIENT_INTERACT_FINISHED, -1)
+#define GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS	pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \
+										GPK_CLIENT_INTERACT_CONFIRM_DEPS, \
+										GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \
+										GPK_CLIENT_INTERACT_PROGRESS, -1)
+#define GPK_CLIENT_INTERACT_WARNING			pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, -1)
+#define GPK_CLIENT_INTERACT_WARNING_PROGRESS		pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_PROGRESS, -1)
+
+GQuark		 gpk_dbus_task_error_quark		(void);
+GType		 gpk_dbus_task_get_type			(void);
+GType		 gpk_dbus_task_error_get_type		(void);
+GpkDbusTask	*gpk_dbus_task_new			(void);
+
+/* methods that expect a DBusGMethodInvocation return */
+void		 gpk_dbus_task_is_installed		(GpkDbusTask	*task,
+							 const gchar	*package_name);
+void		 gpk_dbus_task_search_file		(GpkDbusTask	*task,
+							 const gchar	*search_file);
+void		 gpk_dbus_task_install_package_files	(GpkDbusTask	*task,
+							 gchar		**files_rel);
+void		 gpk_dbus_task_install_provide_files	(GpkDbusTask	*task,
+							 gchar		**full_paths);
+void		 gpk_dbus_task_install_mime_types	(GpkDbusTask	*task,
+							 gchar		**mime_types);
+void		 gpk_dbus_task_install_gstreamer_resources (GpkDbusTask	*task,
+							 gchar		**codec_names);
+void		 gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *task,
+							 gchar		**fonts);
+void		 gpk_dbus_task_install_package_names	(GpkDbusTask	*task,
+							 gchar		**packages);
+void		 gpk_dbus_task_install_catalogs		(GpkDbusTask	*task,
+							 gchar		**filenames);
+
+/* set state */
+gboolean	 gpk_dbus_task_set_interaction		(GpkDbusTask	*task,
+							 PkBitfield	 interact);
+gboolean	 gpk_dbus_task_set_timeout		(GpkDbusTask	*task,
+							 gint		 timeout);
+gboolean	 gpk_dbus_task_set_timestamp		(GpkDbusTask	*task,
+							 guint		 timeout);
+gboolean	 gpk_dbus_task_set_context		(GpkDbusTask	*task,
+							 DBusGMethodInvocation *context);
+gboolean	 gpk_dbus_task_set_xid			(GpkDbusTask	*task,
+							 guint		 xid);
+gboolean	 gpk_dbus_task_set_exec			(GpkDbusTask	*task,
+							 const gchar	*exec);
+
+G_END_DECLS
+
+#endif /* __GPK_DBUS_TASK_H */

Modified: trunk/src/gpk-dbus.c
==============================================================================
--- trunk/src/gpk-dbus.c	(original)
+++ trunk/src/gpk-dbus.c	Tue Apr 14 16:28:59 2009
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2008 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2008-2009 Richard Hughes <richard hughsie com>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -47,8 +47,8 @@
 #include "egg-string.h"
 
 #include "gpk-dbus.h"
+#include "gpk-dbus-task.h"
 #include "gpk-x11.h"
-#include "gpk-client.h"
 #include "gpk-common.h"
 
 static void     gpk_dbus_finalize	(GObject	*object);
@@ -57,10 +57,10 @@
 
 struct GpkDbusPrivate
 {
-	GpkClient		*gclient;
-	PkClient		*client;
 	GConfClient		*gconf_client;
-	gint			 timeout;
+	gint			 timeout_tmp;
+	GpkX11			*x11;
+	GPtrArray		*array;
 };
 
 G_DEFINE_TYPE (GpkDbus, gpk_dbus, G_TYPE_OBJECT)
@@ -152,429 +152,6 @@
 }
 
 /**
- * gpk_dbus_set_parent_window:
- **/
-static void
-gpk_dbus_set_parent_window (GpkDbus *dbus, guint32 xid, guint32 timestamp)
-{
-	GpkX11 *x11;
-
-	/* set the parent window */
-	gpk_client_set_parent_xid (dbus->priv->gclient, xid);
-
-	/* try to get the user time of the window if not provided */
-	if (timestamp == 0 && xid != 0) {
-		x11 = gpk_x11_new ();
-		gpk_x11_set_xid (x11, xid);
-		timestamp = gpk_x11_get_user_time (x11);
-		g_object_unref (x11);
-	}
-
-	/* set the last interaction */
-	gpk_client_update_timestamp (dbus->priv->gclient, timestamp);
-}
-
-/**
- * gpk_dbus_install_local_file:
- **/
-void
-gpk_dbus_install_local_file (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *full_path, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar **full_paths;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallLocalFile method called: %s", full_path);
-
-	/* check sender */
-	sender = dbus_g_method_get_sender (context);
-
-	/* just convert from char* to char** */
-	full_paths = g_strsplit (full_path, "|", 1);
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_local_files (dbus->priv->gclient, full_paths, &error_local);
-	g_strfreev (full_paths);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_provide_file:
- **/
-void
-gpk_dbus_install_provide_file (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *full_path, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallProvideFile method called: %s", full_path);
-
-	/* set modality */
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_provide_file (dbus->priv->gclient, full_path, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_package_name:
- **/
-void
-gpk_dbus_install_package_name (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *package_name, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar **package_names;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallPackageName method called: %s", package_name);
-
-	/* check sender */
-	sender = dbus_g_method_get_sender (context);
-
-	/* just convert from char* to char** */
-	package_names = g_strsplit (package_name, "|", 1);
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_package_names (dbus->priv->gclient, package_names, &error_local);
-	g_strfreev (package_names);
-
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-#if 0
-/**
- * gpk_dbus_install_package_names:
- **/
-void
-gpk_dbus_install_package_names (GpkDbus *dbus, guint32 xid, guint32 timestamp, gchar **package_names, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallPackageNames method called: %s", package_names[0]);
-
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_package_names (dbus->priv->gclient, package_names, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-#endif
-
-/**
- * gpk_dbus_install_mime_type:
- **/
-void
-gpk_dbus_install_mime_type (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *mime_type, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallMimeType method called: %s", mime_type);
-
-	/* set modality */
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_mime_type (dbus->priv->gclient, mime_type, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_gstreamer_codecs:
- **/
-void
-gpk_dbus_install_gstreamer_codecs (GpkDbus *dbus, guint32 xid, guint32 timestamp, GPtrArray *codecs, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-	guint i;
-	GValue *value;
-	gchar *description;
-	gchar *detail;
-	gchar *encoded;
-	GPtrArray *array;
-	GValueArray *varray;
-	gchar **codec_strings;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallGStreamerCodecs method called");
-
-	/* set modality */
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* unwrap and turn into a GPtrArray */
-	array = g_ptr_array_new ();
-	for (i=0; i<codecs->len; i++) {
-		varray = (GValueArray *) g_ptr_array_index (codecs, i);
-		value = g_value_array_get_nth (varray, 0);
-		description = g_value_dup_string (value);
-		value = g_value_array_get_nth (varray, 1);
-		detail = g_value_dup_string (value);
-		encoded = g_strdup_printf ("%s|%s", description, detail);
-		g_ptr_array_add (array, encoded);
-		g_free (description);
-		g_free (detail);
-	}
-
-	/* convert to an strv */
-	codec_strings = pk_ptr_array_to_strv (array);
-	g_ptr_array_foreach (array, (GFunc) g_free, NULL);
-	g_ptr_array_free (array, TRUE);
-
-	/* do the action */
-	ret = gpk_client_install_gstreamer_codecs (dbus->priv->gclient, codec_strings, &error_local);
-	g_strfreev (codec_strings);
-
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_fonts:
- **/
-void
-gpk_dbus_install_fonts (GpkDbus *dbus, guint32 xid, guint32 timestamp, gchar **fonts, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallFonts method called: %s", fonts[0]);
-
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_fonts (dbus->priv->gclient, fonts, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_font:
- **/
-void
-gpk_dbus_install_font (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *font, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar *exec;
-	gchar **fonts;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallFont method called: %s", font);
-
-	/* set modality */
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	fonts = g_strsplit (font, "|", 1);
-	ret = gpk_client_install_fonts (dbus->priv->gclient, fonts, &error_local);
-	g_strfreev (fonts);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
- * gpk_dbus_install_catalog:
- **/
-void
-gpk_dbus_install_catalog (GpkDbus *dbus, guint32 xid, guint32 timestamp, const gchar *catalog_file, DBusGMethodInvocation *context)
-{
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-	gchar *sender;
-	gchar **catalog_files;
-	gchar *exec;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallCatalog method called: %s", catalog_file);
-
-	/* check sender */
-	sender = dbus_g_method_get_sender (context);
-
-	/* just convert from char* to char** */
-	catalog_files = g_strsplit (catalog_file, "|", 1);
-	gpk_dbus_set_parent_window (dbus, xid, timestamp);
-
-	/* get the program name and set */
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-	g_free (sender);
-	g_free (exec);
-
-	/* do the action */
-	ret = gpk_client_install_catalogs (dbus->priv->gclient, catalog_files, &error_local);
-	g_strfreev (catalog_files);
-
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
-}
-
-/**
  * gpk_dbus_set_interaction_from_text:
  **/
 static void
@@ -630,239 +207,122 @@
 }
 
 /**
- * gpk_dbus_set_interaction:
+ * gpk_dbus_parse_interaction:
  **/
 static void
-gpk_dbus_set_interaction (GpkDbus *dbus, const gchar *interaction)
+gpk_dbus_parse_interaction (GpkDbus *dbus, const gchar *interaction, PkBitfield *interact, gint *timeout)
 {
-	PkBitfield interact = 0;
 	gchar *policy;
 
-	/* set default */
-	dbus->priv->timeout = -1;
+	/* set temp default */
+	*interact = 0;
+	dbus->priv->timeout_tmp = -1;
 
 	/* get default policy from gconf */
 	policy = gconf_client_get_string (dbus->priv->gconf_client, GPK_CONF_DBUS_DEFAULT_INTERACTION, NULL);
 	if (policy != NULL) {
 		egg_debug ("default is %s", policy);
-		gpk_dbus_set_interaction_from_text (&interact, &dbus->priv->timeout, policy);
+		gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy);
 	}
 	g_free (policy);
 
 	/* now override with policy from client */
-	gpk_dbus_set_interaction_from_text (&interact, &dbus->priv->timeout, interaction);
+	gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, interaction);
 	egg_debug ("client is %s", interaction);
 
 	/* now override with enforced policy from gconf */
 	policy = gconf_client_get_string (dbus->priv->gconf_client, GPK_CONF_DBUS_ENFORCED_INTERACTION, NULL);
 	if (policy != NULL) {
 		egg_debug ("enforced is %s", policy);
-		gpk_dbus_set_interaction_from_text (&interact, &dbus->priv->timeout, policy);
+		gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy);
 	}
 	g_free (policy);
 
-	/* set the interaction mode */
-	egg_debug ("interact=%i", (gint) interact);
-	gpk_client_set_interaction (dbus->priv->gclient, interact);
-
-	/* set the timeout locally and in the helper client */
-	egg_debug ("timeout=%i", dbus->priv->timeout);
-	gpk_client_set_timeout (dbus->priv->gclient, dbus->priv->timeout);
+	/* copy from temp */
+	*timeout = dbus->priv->timeout_tmp;
 }
 
 /**
- * gpk_dbus_set_context:
+ * gpk_dbus_create_task:
  **/
-static void
-gpk_dbus_set_context (GpkDbus *dbus, DBusGMethodInvocation *context)
+static GpkDbusTask *
+gpk_dbus_create_task (GpkDbus *dbus, guint32 xid, const gchar *interaction, DBusGMethodInvocation *context)
 {
+	GpkDbusTask *task;
+	PkBitfield interact = 0;
+	gint timeout = 0;
 	gchar *sender;
 	gchar *exec;
+	guint timestamp = 0;
 
-	/* get the program name and set */
-	sender = dbus_g_method_get_sender (context);
-	exec = gpk_dbus_get_exec_for_sender (sender);
-	gpk_client_set_parent_exec (dbus->priv->gclient, exec);
-
-	g_free (sender);
-	g_free (exec);
-}
+	task = gpk_dbus_task_new ();
 
-#if 0
-/**
- * gpk_dbus_is_package_installed:
- **/
-gboolean
-gpk_dbus_is_package_installed (GpkDbus *dbus, const gchar *package_name, gboolean *installed, GError **error)
-{
-	gboolean ret;
-	GError *error_local = NULL;
-	PkPackageList *list = NULL;
-	gchar **package_names = NULL;
-
-	g_return_val_if_fail (PK_IS_DBUS (dbus), FALSE);
+	/* work out what interaction the task should use */
+	gpk_dbus_parse_interaction (dbus, interaction, &interact, &timeout);
 
-	/* reset */
-	ret = pk_client_reset (dbus->priv->client, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
-	}
+	/* set interaction mode */
+	egg_debug ("interact=%i", (gint) interact);
+	gpk_dbus_task_set_interaction (task, interact);
 
 	/* set timeout */
-	pk_client_set_timeout (dbus->priv->client, dbus->priv->timeout, NULL);
+	egg_debug ("timeout=%i", timeout);
+	gpk_dbus_task_set_timeout (task, timeout);
 
-	/* get the package list for the installed packages */
-	package_names = g_strsplit (package_name, "|", 1);
-	ret = pk_client_resolve (dbus->priv->client, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_names, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
+	/* set the parent window */
+	gpk_dbus_task_set_xid (task, xid);
+
+	/* try to get the user time of the window */
+	if (xid != 0) {
+		gpk_x11_set_xid (dbus->priv->x11, xid);
+		timestamp = gpk_x11_get_user_time (dbus->priv->x11);
 	}
 
-	/* more than one entry? */
-	list = pk_client_get_package_list (dbus->priv->client);
-	*installed = (PK_OBJ_LIST(list)->len > 0);
-out:
-	if (list != NULL)
-		g_object_unref (list);
-	g_strfreev (package_names);
-	return ret;
-}
-#endif
+	/* set the context for the return values */
+	gpk_dbus_task_set_context (task, context);
 
-/**
- * gpk_dbus_is_installed:
- **/
-gboolean
-gpk_dbus_is_installed (GpkDbus *dbus, const gchar *package_name, const gchar *interaction, gboolean *installed, GError **error)
-{
-	gboolean ret;
-	GError *error_local = NULL;
-	PkPackageList *list = NULL;
-	gchar **package_names = NULL;
+	/* set the last interaction */
+	gpk_dbus_task_set_timestamp (task, timestamp);
 
-	g_return_val_if_fail (PK_IS_DBUS (dbus), FALSE);
+	/* set the window for the modal and timestamp */
+	gpk_dbus_task_set_xid (task, xid);
 
-	/* process wait command */
-	gpk_dbus_set_interaction (dbus, interaction);
+	/* get the program name and set */
+	sender = dbus_g_method_get_sender (context);
+	exec = gpk_dbus_get_exec_for_sender (sender);
+	gpk_dbus_task_set_exec (task, exec);
 
-	/* reset */
-	ret = pk_client_reset (dbus->priv->client, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
-	}
+	/* unref on delete */
+	//g_signal_connect...
 
-	/* set timeout */
-	pk_client_set_timeout (dbus->priv->client, dbus->priv->timeout, NULL);
+	/* add to array */
+	g_ptr_array_add (dbus->priv->array, task);
 
-	/* get the package list for the installed packages */
-	package_names = g_strsplit (package_name, "|", 1);
-	ret = pk_client_resolve (dbus->priv->client, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_names, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
-	}
-
-	/* more than one entry? */
-	list = pk_client_get_package_list (dbus->priv->client);
-	*installed = (PK_OBJ_LIST(list)->len > 0);
-out:
-	if (list != NULL)
-		g_object_unref (list);
-	g_strfreev (package_names);
-	return ret;
+	g_free (sender);
+	g_free (exec);
+	return task;
 }
 
+
 /**
- * gpk_dbus_search_file:
+ * gpk_dbus_is_installed:
  **/
-gboolean
-gpk_dbus_search_file (GpkDbus *dbus, const gchar *file_name, const gchar *interaction, gboolean *installed, gchar **package_name, GError **error)
+void
+gpk_dbus_is_installed (GpkDbus *dbus, const gchar *package_name, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error_local = NULL;
-	PkPackageList *list = NULL;
-	const PkPackageObj *obj;
-
-	g_return_val_if_fail (PK_IS_DBUS (dbus), FALSE);
-
-	/* process wait command */
-	gpk_dbus_set_interaction (dbus, interaction);
-
-	/* reset */
-	ret = pk_client_reset (dbus->priv->client, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to get installed status: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
-	}
-
-	/* set timeout */
-	pk_client_set_timeout (dbus->priv->client, dbus->priv->timeout, NULL);
-
-	/* get the package list for the installed packages */
-	ret = pk_client_search_file (dbus->priv->client, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), file_name, &error_local);
-	if (!ret) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_INTERNAL_ERROR, "failed to search for file: %s", error_local->message);
-		g_error_free (error_local);
-		goto out;
-	}
-
-	/* more than one entry? */
-	list = pk_client_get_package_list (dbus->priv->client);
-	if (PK_OBJ_LIST(list)->len < 1) {
-		*error = g_error_new (GPK_DBUS_ERROR, GPK_DBUS_ERROR_NO_PACKAGES_FOUND, "could not find package providing file");
-		ret = FALSE;
-		goto out;
-	}
-
-	/* get the package name too */
-	*installed = TRUE;
-	obj = pk_package_list_get_obj (list, 0);
-	*package_name = g_strdup (obj->id->name);
-
-out:
-	if (list != NULL)
-		g_object_unref (list);
-	return ret;
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, 0, interaction, context);
+	gpk_dbus_task_is_installed (task, package_name);
 }
 
 /**
- * gpk_dbus_install_provide_files:
+ * gpk_dbus_search_file:
  **/
 void
-gpk_dbus_install_provide_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
+gpk_dbus_search_file (GpkDbus *dbus, const gchar *file_name, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallProvideFiles method called: %s", files[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_provide_file (dbus->priv->gclient, files[0], &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, 0, interaction, context);
+	gpk_dbus_task_search_file (task, file_name);
 }
 
 /**
@@ -871,30 +331,20 @@
 void
 gpk_dbus_install_package_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallPackageFiles method called: %s", files[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_local_files (dbus->priv->gclient, files, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_package_files (task, files);
+}
 
-	dbus_g_method_return (context);
+/**
+ * gpk_dbus_install_provide_files:
+ **/
+void
+gpk_dbus_install_provide_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_provide_files (task, files);
 }
 
 /**
@@ -903,30 +353,9 @@
 void
 gpk_dbus_install_package_names (GpkDbus *dbus, guint32 xid, gchar **packages, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallPackageNames method called: %s", packages[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_package_names (dbus->priv->gclient, packages, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_package_names (task, packages);
 }
 
 /**
@@ -935,30 +364,9 @@
 void
 gpk_dbus_install_mime_types (GpkDbus *dbus, guint32 xid, gchar **mime_types, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallMimeTypes method called: %s", mime_types[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_mime_type (dbus->priv->gclient, mime_types[0], &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_mime_types (task, mime_types);
 }
 
 /**
@@ -967,30 +375,9 @@
 void
 gpk_dbus_install_fontconfig_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallFontconfigResources method called: %s", resources[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_fonts (dbus->priv->gclient, resources, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_fontconfig_resources (task, resources);
 }
 
 /**
@@ -999,30 +386,9 @@
 void
 gpk_dbus_install_gstreamer_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context)
 {
-	gboolean ret;
-	GError *error;
-	GError *error_local = NULL;
-
-	g_return_if_fail (PK_IS_DBUS (dbus));
-
-	egg_debug ("InstallGStreamerResources method called: %s", resources[0]);
-
-	/* set common parameters */
-	gpk_dbus_set_parent_window (dbus, xid, 0);
-	gpk_dbus_set_interaction (dbus, interaction);
-	gpk_dbus_set_context (dbus, context);
-
-	/* do the action */
-	ret = gpk_client_install_gstreamer_codecs (dbus->priv->gclient, resources, &error_local);
-	if (!ret) {
-		error = g_error_new (GPK_DBUS_ERROR, error_local->code,
-				     "Method failed: %s", error_local->message);
-		g_error_free (error_local);
-		dbus_g_method_return_error (context, error);
-		return;
-	}
-
-	dbus_g_method_return (context);
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_gstreamer_resources (task, resources);
 }
 
 /**
@@ -1045,14 +411,10 @@
 gpk_dbus_init (GpkDbus *dbus)
 {
 	dbus->priv = GPK_DBUS_GET_PRIVATE (dbus);
-	dbus->priv->timeout = -1;
+	dbus->priv->timeout_tmp = -1;
 	dbus->priv->gconf_client = gconf_client_get_default ();
-	dbus->priv->client = pk_client_new ();
-	pk_client_set_use_buffer (dbus->priv->client, TRUE, NULL);
-	pk_client_set_synchronous (dbus->priv->client, TRUE, NULL);
-
-	dbus->priv->gclient = gpk_client_new ();
-	gpk_client_set_interaction (dbus->priv->gclient, GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS);
+	dbus->priv->array = g_ptr_array_new ();
+	dbus->priv->x11 = gpk_x11_new ();
 }
 
 /**
@@ -1067,9 +429,10 @@
 
 	dbus = GPK_DBUS (object);
 	g_return_if_fail (dbus->priv != NULL);
-	g_object_unref (dbus->priv->client);
-	g_object_unref (dbus->priv->gclient);
+	g_ptr_array_foreach (dbus->priv->array, (GFunc) g_object_unref, NULL);
+	g_ptr_array_free (dbus->priv->array, TRUE);
 	g_object_unref (dbus->priv->gconf_client);
+	g_object_unref (dbus->priv->x11);
 
 	G_OBJECT_CLASS (gpk_dbus_parent_class)->finalize (object);
 }

Modified: trunk/src/gpk-dbus.h
==============================================================================
--- trunk/src/gpk-dbus.h	(original)
+++ trunk/src/gpk-dbus.h	Tue Apr 14 16:28:59 2009
@@ -64,72 +64,21 @@
 GType		 gpk_dbus_get_type			(void);
 GpkDbus		*gpk_dbus_new				(void);
 
-void		 gpk_dbus_install_local_file		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*full_path,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_provide_file		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*full_path,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_package_name		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*package_name,
-							 DBusGMethodInvocation *context);
-#if 0
-void		 gpk_dbus_install_package_names		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 gchar		**package_names,
-							 DBusGMethodInvocation *context);
-#endif
-void		 gpk_dbus_install_mime_type		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*mime_type,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_gstreamer_codecs	(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 GPtrArray	*codecs,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_font			(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*font_desc,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_fonts			(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 gchar		**font_descs,
-							 DBusGMethodInvocation *context);
-void		 gpk_dbus_install_catalog		(GpkDbus	*dbus,
-							 guint32	 xid,
-							 guint32	 timestamp,
-							 const gchar	*catalog_file,
-							 DBusGMethodInvocation *context);
-#if 0
-gboolean	 gpk_dbus_is_package_installed		(GpkDbus	*dbus,
-							 const gchar	*package_name,
-							 gboolean	*installed,
-							 GError		**error);
-#endif
+//void		 gpk_dbus_install_catalog		(GpkDbus	*dbus,
+//							 guint32	 xid,
+//							 guint32	 timestamp,
+//							 const gchar	*catalog_file,
+//							 DBusGMethodInvocation *context);
 
 /* org.freedesktop.PackageKit.Query */
-gboolean	 gpk_dbus_is_installed			(GpkDbus	*dbus,
+void		 gpk_dbus_is_installed			(GpkDbus	*dbus,
 							 const gchar	*package_name,
 							 const gchar	*interaction,
-							 gboolean	*installed,
-							 GError		**error);
-gboolean	 gpk_dbus_search_file			(GpkDbus	*dbus,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_search_file			(GpkDbus	*dbus,
 							 const gchar	*file_name,
 							 const gchar	*interaction,
-							 gboolean	*installed,
-							 gchar		**package_name,
-							 GError		**error);
+							 DBusGMethodInvocation *context);
 
 /* org.freedesktop.PackageKit.Modify */
 void		 gpk_dbus_install_provide_files		(GpkDbus	*dbus,

Modified: trunk/src/gpk-dialog.c
==============================================================================
--- trunk/src/gpk-dialog.c	(original)
+++ trunk/src/gpk-dialog.c	Tue Apr 14 16:28:59 2009
@@ -273,7 +273,7 @@
 	checked = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
 	egg_debug ("Changing %s to %i", key, checked);
 	gconf_client = gconf_client_get_default ();
-	gconf_client_set_bool (gconf_client, key, checked, NULL);
+	gconf_client_set_bool (gconf_client, key, !checked, NULL);
 	g_object_unref (gconf_client);
 }
 
@@ -284,11 +284,20 @@
 gpk_dialog_embed_do_not_show_widget (GtkDialog *dialog, const gchar *key)
 {
 	GtkWidget *widget;
+	gboolean checked;
+	GConfClient *gconf_client;
 
 	/* add a checkbutton for deps screen */
 	widget = gtk_check_button_new_with_label (_("Do not show this again"));
 	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_client_checkbutton_show_depends_cb), (gpointer) key);
 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), widget);
+
+	/* checked? */
+	gconf_client = gconf_client_get_default ();
+	checked = gconf_client_get_bool (gconf_client, key, NULL);
+	g_object_unref (gconf_client);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), !checked);
+
 	gtk_widget_show (widget);
 	return TRUE;
 }

Modified: trunk/src/gpk-enum.c
==============================================================================
--- trunk/src/gpk-enum.c	(original)
+++ trunk/src/gpk-enum.c	Tue Apr 14 16:28:59 2009
@@ -310,6 +310,36 @@
 }
 
 /**
+ * gpk_media_type_enum_to_localised_text:
+ **/
+const gchar *
+gpk_media_type_enum_to_localised_text (PkMediaTypeEnum type)
+{
+	const gchar *text = NULL;
+	switch (type) {
+	case PK_MEDIA_TYPE_ENUM_CD:
+		/* TRANSLATORS: this is compact disk (CD) media */
+		text = _("CD");
+		break;
+	case PK_MEDIA_TYPE_ENUM_DVD:
+		/* TRANSLATORS: this is digital versatile disk (DVD) media */
+		text = _("DVD");
+		break;
+	case PK_MEDIA_TYPE_ENUM_DISC:
+		/* TRANSLATORS: this is either CD or DVD media */
+		text = _("disc");
+		break;
+	case PK_MEDIA_TYPE_ENUM_UNKNOWN:
+		/* TRANSLATORS: this is generic media of unknown type that we will install from */
+		text = _("media");
+		break;
+	default:
+		egg_warning ("Unknown media type");
+	}
+	return text;
+}
+
+/**
  * gpk_error_enum_to_localised_text:
  **/
 const gchar *
@@ -455,6 +485,9 @@
 	case PK_ERROR_ENUM_NO_SPACE_ON_DEVICE:
 		text = _("No space is left on the disk");
 		break;
+	case PK_ERROR_ENUM_MEDIA_CHANGE_REQUIRED:
+		text = _("A media change is required");
+		break;
 	default:
 		egg_warning ("Unknown error");
 	}
@@ -638,6 +671,9 @@
 		text = _("There is insufficient space on the device.\n"
 			 "Free some space on the system disk to perform this operation.");
 		break;
+	case PK_ERROR_ENUM_MEDIA_CHANGE_REQUIRED:
+		text = _("Additional media is required to complete the transaction.");
+		break;
 	default:
 		egg_warning ("Unknown error, please report a bug at " GPK_BUGZILLA_URL ".\n"
 			    "More information is available in the detailed report.");

Modified: trunk/src/gpk-enum.h
==============================================================================
--- trunk/src/gpk-enum.h	(original)
+++ trunk/src/gpk-enum.h	Tue Apr 14 16:28:59 2009
@@ -78,6 +78,8 @@
 GpkUpdateEnum	 gpk_update_enum_from_text		(const gchar	*update);
 const gchar	*gpk_update_enum_to_text		(GpkUpdateEnum	 update);
 const gchar	*gpk_role_enum_to_icon_name		(PkRoleEnum	 role);
+const gchar	*gpk_media_type_enum_to_localised_text	(PkMediaTypeEnum type)
+							 G_GNUC_CONST;
 const gchar	*gpk_info_enum_to_localised_text	(PkInfoEnum	 info)
 							 G_GNUC_CONST;
 const gchar	*gpk_info_enum_to_localised_past	(PkInfoEnum	 info)

Modified: trunk/src/gpk-error.c
==============================================================================
--- trunk/src/gpk-error.c	(original)
+++ trunk/src/gpk-error.c	Tue Apr 14 16:28:59 2009
@@ -71,7 +71,6 @@
 	guint retval;
 	GError *error = NULL;
 
-	g_return_val_if_fail (title != NULL, FALSE);
 	g_return_val_if_fail (message != NULL, FALSE);
 
 	/* get UI */

Modified: trunk/src/gpk-firmware.c
==============================================================================
--- trunk/src/gpk-firmware.c	(original)
+++ trunk/src/gpk-firmware.c	Tue Apr 14 16:28:59 2009
@@ -42,7 +42,6 @@
 #include "egg-debug.h"
 #include "egg-string.h"
 
-#include "gpk-client.h"
 #include "gpk-common.h"
 #include "gpk-firmware.h"
 
@@ -55,7 +54,8 @@
 
 struct GpkFirmwarePrivate
 {
-	GPtrArray		*array_found;
+	PkClient		*client_primary;
+	PkPackageList		*packages_found;
 	GPtrArray		*array_requested;
 	GConfClient		*gconf_client;
 };
@@ -68,28 +68,26 @@
 static gboolean
 gpk_firmware_install_file (GpkFirmware *firmware)
 {
-	guint i;
 	gboolean ret;
-	GpkClient *gclient;
-	GPtrArray *array;
 	GError *error = NULL;
-	const gchar *filename;
+	gchar **package_ids;
 
-	gclient = gpk_client_new ();
-	array = firmware->priv->array_found;
-
-	/* try to install each firmware file */
-	for (i=0; i<array->len; i++) {
-		filename = g_ptr_array_index (array, i);
-		gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_WARNING_PROGRESS);
-		ret = gpk_client_install_provide_file (gclient, filename, &error);
-		if (!ret) {
-			egg_warning ("failed to install provide file: %s", error->message);
-			g_error_free (error);
-			error = NULL;
-		}
+	/* install all of the firmware files */
+	package_ids = pk_package_list_to_strv (firmware->priv->packages_found);
+	ret = pk_client_reset (firmware->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to reset: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	ret = pk_client_install_packages (firmware->priv->client_primary, package_ids, &error);
+	if (!ret) {
+		egg_warning ("failed to install provide file: %s", error->message);
+		g_error_free (error);
+		goto out;
 	}
-	g_object_unref (gclient);
+out:
+	g_strfreev (package_ids);
 	return ret;
 }
 
@@ -116,39 +114,42 @@
  * @firmware: This class instance
  * @filename: Firmware to search for
  **/
-static gboolean
+static PkPackageObj *
 gpk_firmware_check_available (GpkFirmware *firmware, const gchar *filename)
 {
 	gboolean ret;
 	guint length = 0;
-	PkClient *client = NULL;
 	PkPackageList *list = NULL;
 	GError *error = NULL;
+	PkPackageObj *obj = NULL;
 
 	/* actually check we can provide the firmware */
-	client = pk_client_new ();
-	pk_client_set_synchronous (client, TRUE, NULL);
-	pk_client_set_use_buffer (client, TRUE, NULL);
-	ret = pk_client_search_file (client, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED), filename, &error);
+	ret = pk_client_reset (firmware->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to reset: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	ret = pk_client_search_file (firmware->priv->client_primary, pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED), filename, &error);
 	if (!ret) {
 		egg_warning ("failed to search file %s: %s", filename, error->message);
 		g_error_free (error);
-		error = NULL;
 		goto out;
 	}
 
 	/* make sure we have one package */
-	list = pk_client_get_package_list (client);
+	list = pk_client_get_package_list (firmware->priv->client_primary);
 	length = pk_package_list_get_size (list);
-	g_object_unref (list);
 	if (length == 0)
 		egg_debug ("no package providing %s found", filename);
 	else if (length != 1)
 		egg_warning ("not one package providing %s found (%i)", filename, length);
-
+	else
+		obj = pk_package_obj_copy (pk_package_list_get_obj (list, 0));
 out:
-	g_object_unref (client);
-	return (length == 1);
+	if (list != NULL)
+		g_object_unref (list);
+	return obj;
 }
 
 /**
@@ -158,15 +159,15 @@
 static gboolean
 gpk_firmware_timeout_cb (gpointer data)
 {
-	guint i, j;
+	guint i;
 	gboolean ret;
 	const gchar *filename;
 	const gchar *message;
-	gchar *duplicate;
 	GpkFirmware *firmware = GPK_FIRMWARE (data);
 	NotifyNotification *notification;
 	GPtrArray *array;
 	GError *error = NULL;
+	PkPackageObj *obj = NULL;
 
 	/* debug so we can catch polling */
 	egg_debug ("polling check");
@@ -176,35 +177,21 @@
 	for (i=0; i<array->len; i++) {
 		filename = g_ptr_array_index (array, i);
 		/* save to new array if we found one package for this file */
-		ret = gpk_firmware_check_available (firmware, filename);
-		if (ret)
-			g_ptr_array_add (firmware->priv->array_found, g_strdup (filename));
+		obj = gpk_firmware_check_available (firmware, filename);
+		if (obj != NULL) {
+			pk_obj_list_add (PK_OBJ_LIST (firmware->priv->packages_found), obj);
+			pk_package_obj_free (obj);
+		}
 	}
 
 	/* nothing to do */
-	array = firmware->priv->array_found;
-	if (array->len == 0) {
+	if (pk_package_list_get_size (firmware->priv->packages_found) == 0) {
 		egg_debug ("no packages providing any of the missing firmware");
 		goto out;
 	}
 
 	/* check we don't want the same package more than once */
-	for (i=0; i<array->len; i++) {
-		for (j=0; j<array->len; j++) {
-			duplicate = g_ptr_array_index (array, j);
-			if (i != j && egg_strequal (g_ptr_array_index (array, i), duplicate)) {
-				g_free (duplicate);
-				g_ptr_array_remove_index_fast (array, j);
-			}
-		}
-	}
-
-	/* debugging */
-	egg_debug ("need to install:");
-	for (i=0; i<array->len; i++) {
-		filename = g_ptr_array_index (array, i);
-		egg_debug ("%s", filename);
-	}
+	pk_obj_list_remove_duplicate (PK_OBJ_LIST (firmware->priv->packages_found));
 
 	/* TRANSLATORS: we need another package to keep udev quiet */
 	message = _("Additional firmware is required to make hardware in this computer function correctly.");
@@ -330,9 +317,12 @@
 	GPtrArray *array;
 
 	firmware->priv = GPK_FIRMWARE_GET_PRIVATE (firmware);
-	firmware->priv->array_found = g_ptr_array_new ();
+	firmware->priv->packages_found = pk_package_list_new ();
 	firmware->priv->array_requested = g_ptr_array_new ();
 	firmware->priv->gconf_client = gconf_client_get_default ();
+	firmware->priv->client_primary = pk_client_new ();
+	pk_client_set_synchronous (firmware->priv->client_primary, TRUE, NULL);
+	pk_client_set_use_buffer (firmware->priv->client_primary, TRUE, NULL);
 
 	/* should we check and show the user */
 	ret = gconf_client_get_bool (firmware->priv->gconf_client, GPK_CONF_ENABLE_CHECK_FIRMWARE, NULL);
@@ -405,10 +395,10 @@
 	firmware = GPK_FIRMWARE (object);
 
 	g_return_if_fail (firmware->priv != NULL);
-	g_ptr_array_foreach (firmware->priv->array_found, (GFunc) g_free, NULL);
-	g_ptr_array_free (firmware->priv->array_found, TRUE);
 	g_ptr_array_foreach (firmware->priv->array_requested, (GFunc) g_free, NULL);
 	g_ptr_array_free (firmware->priv->array_requested, TRUE);
+	g_object_unref (firmware->priv->packages_found);
+	g_object_unref (firmware->priv->client_primary);
 	g_object_unref (firmware->priv->gconf_client);
 
 	G_OBJECT_CLASS (gpk_firmware_parent_class)->finalize (object);

Modified: trunk/src/gpk-hardware.c
==============================================================================
--- trunk/src/gpk-hardware.c	(original)
+++ trunk/src/gpk-hardware.c	Tue Apr 14 16:28:59 2009
@@ -44,7 +44,6 @@
 #include "egg-debug.h"
 #include "egg-string.h"
 
-#include "gpk-client.h"
 #include "gpk-common.h"
 #include "gpk-hardware.h"
 
@@ -74,19 +73,21 @@
 gpk_hardware_install_package (GpkHardware *hardware)
 {
 	GError *error = NULL;
-	GpkClient *gclient = NULL;
+	PkClient *client = NULL;
 	gboolean ret;
 
-	gclient = gpk_client_new ();
+	client = pk_client_new ();
 
-	ret = gpk_client_install_package_ids (gclient, hardware->priv->package_ids, &error);
+	/* FIXME: this needs to be async and connect up to the repo signature stuff */
+	pk_client_set_synchronous (client, TRUE, NULL);
+	ret = pk_client_install_packages (client, hardware->priv->package_ids, &error);
 	if (!ret) {
 		egg_warning ("failed to install package: %s", error->message);
 		g_error_free (error);
 		error = NULL;
 	}
 
-	g_object_unref (gclient);
+	g_object_unref (client);
 	return ret;
 }
 

Added: trunk/src/gpk-helper-chooser.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-chooser.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,355 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+#include "gpk-helper-chooser.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-enum.h"
+#include "gpk-desktop.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_chooser_finalize	(GObject	  *object);
+
+#define GPK_HELPER_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserPrivate))
+
+struct GpkHelperChooserPrivate
+{
+	GtkBuilder		*builder;
+	PkDesktop		*desktop;
+	gchar			*package_id;
+	GtkListStore		*list_store;
+};
+
+enum {
+	GPK_HELPER_CHOOSER_EVENT,
+	GPK_HELPER_CHOOSER_LAST_SIGNAL
+};
+
+enum {
+	GPK_CHOOSER_COLUMN_ICON,
+	GPK_CHOOSER_COLUMN_TEXT,
+	GPK_CHOOSER_COLUMN_ID,
+	GPK_CHOOSER_COLUMN_LAST
+};
+
+static guint signals [GPK_HELPER_CHOOSER_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperChooser, gpk_helper_chooser, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_chooser_button_install_cb:
+ **/
+static void
+gpk_helper_chooser_button_install_cb (GtkWidget *widget, GpkHelperChooser *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_YES, helper->priv->package_id);
+}
+
+/**
+ * gpk_helper_chooser_button_cancel_cb:
+ **/
+static void
+gpk_helper_chooser_button_cancel_cb (GtkWidget *widget, GpkHelperChooser *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_NO, helper->priv->package_id);
+}
+
+/**
+ * gpk_helper_chooser_button_help_cb:
+ **/
+static void
+gpk_helper_chooser_button_help_cb (GtkWidget *widget, GpkHelperChooser *helper)
+{
+	/* show the help */
+	gpk_gnome_help ("mime-types");
+}
+
+/**
+ * gpk_helper_chooser_treeview_clicked_cb:
+ **/
+static void
+gpk_helper_chooser_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperChooser *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	/* This will only work in single or browse selection mode! */
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		g_free (helper->priv->package_id);
+		gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_ID, &helper->priv->package_id, -1);
+
+		/* show package_id */
+		egg_debug ("selected row is: %s", helper->priv->package_id);
+	} else {
+		egg_debug ("no row selected");
+	}
+}
+
+/**
+ * pk_treeview_add_general_columns:
+ **/
+static void
+pk_treeview_add_general_columns (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* image */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+        g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+	/* TRANSLATORS: column for the application icon */
+	column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer,
+							   "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the application name */
+	column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer,
+							   "markup", GPK_CHOOSER_COLUMN_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+	gtk_tree_view_column_set_expand (column, TRUE);
+}
+
+/**
+ * gpk_helper_chooser_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_chooser_show (GpkHelperChooser *helper, PkPackageList *list)
+{
+	GtkWidget *widget;
+	gchar *text;
+	const gchar *icon_name;
+	guint len;
+	guint i;
+	const PkPackageObj *obj;
+	gchar *package_id;
+	GtkTreeIter iter;
+
+	g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE);
+	g_return_val_if_fail (list != NULL, FALSE);
+
+	/* see what we've got already */
+	len = pk_package_list_get_size (list);
+	for (i=0; i<len; i++) {
+		obj = pk_package_list_get_obj (list, i);
+		egg_debug ("package '%s' got:", obj->id->name);
+
+		/* put formatted text into treeview */
+		gtk_list_store_append (helper->priv->list_store, &iter);
+		text = gpk_package_id_format_twoline (obj->id, obj->summary);
+
+		/* get the icon */
+		icon_name = gpk_desktop_guess_icon_name (helper->priv->desktop, obj->id->name);
+		if (icon_name == NULL)
+			icon_name = gpk_info_enum_to_icon_name (obj->info);
+
+		package_id = pk_package_id_to_string (obj->id);
+		gtk_list_store_set (helper->priv->list_store, &iter,
+				    GPK_CHOOSER_COLUMN_TEXT, text,
+				    GPK_CHOOSER_COLUMN_ID, package_id, -1);
+		g_free (package_id);
+		package_id = NULL;
+		gtk_list_store_set (helper->priv->list_store, &iter, GPK_CHOOSER_COLUMN_ICON, icon_name, -1);
+		g_free (text);
+	}
+
+	/* show window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_show (widget);
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_chooser_set_parent:
+ **/
+gboolean
+gpk_helper_chooser_set_parent (GpkHelperChooser *helper, GtkWindow *window)
+{
+	GtkWindow *widget;
+
+	g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (widget, "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_chooser_class_init:
+ * @klass: The GpkHelperChooserClass
+ **/
+static void
+gpk_helper_chooser_class_init (GpkHelperChooserClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_chooser_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperChooserPrivate));
+	signals [GPK_HELPER_CHOOSER_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperChooserClass, event),
+			      NULL, NULL, gpk_marshal_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+}
+
+/**
+ * gpk_helper_chooser_init:
+ **/
+static void
+gpk_helper_chooser_init (GpkHelperChooser *helper)
+{
+	GtkWidget *widget;
+	guint retval;
+	GError *error = NULL;
+	GtkWidget *button;
+	GtkTreeSelection *selection;
+
+	helper->priv = GPK_HELPER_CHOOSER_GET_PRIVATE (helper);
+
+	helper->priv->package_id = NULL;
+
+	/* get UI */
+	helper->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error);
+	if (error != NULL) {
+		egg_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* connect up default actions */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_helper_chooser_button_cancel_cb), helper);
+
+	/* set icon name */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+	gtk_window_set_title (GTK_WINDOW (widget), _("Applications that can open this type of file"));
+
+	/* set a size, if the screen allows */
+	gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300);
+
+	/* connect up buttons */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_help"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_chooser_button_help_cb), helper);
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_chooser_button_cancel_cb), helper);
+
+	/* TRANSLATORS: button label, install */
+	button = gtk_button_new_with_mnemonic (_("_Install"));
+	g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_chooser_button_install_cb), helper);
+
+	/* TRANSLATORS: button tooltip */
+	gtk_widget_set_tooltip_text (button, _("Install package"));
+
+	/* add to box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	widget = gtk_dialog_get_action_area (GTK_DIALOG(widget));
+	gtk_box_pack_start (GTK_BOX (widget), button, FALSE, FALSE, 0);
+	gtk_widget_show (button);
+
+	/* hide the filter box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter"));
+	gtk_widget_hide (widget);
+
+	/* hide the refresh button */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh"));
+	gtk_widget_hide (widget);
+
+	/* create list stores */
+	helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* create package_id tree view */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple"));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (helper->priv->list_store));
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	g_signal_connect (selection, "changed",
+			  G_CALLBACK (gpk_helper_chooser_treeview_clicked_cb), helper);
+
+	/* add columns to the tree view */
+	pk_treeview_add_general_columns (GTK_TREE_VIEW (widget));
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+
+	/* use PkDesktop to get better icon */
+	helper->priv->desktop = pk_desktop_new ();
+}
+
+/**
+ * gpk_helper_chooser_finalize:
+ **/
+static void
+gpk_helper_chooser_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkHelperChooser *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_CHOOSER (object));
+
+	helper = GPK_HELPER_CHOOSER (object);
+
+	/* hide window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_free (helper->priv->package_id);
+	g_object_unref (helper->priv->builder);
+	g_object_unref (helper->priv->desktop);
+
+	G_OBJECT_CLASS (gpk_helper_chooser_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_chooser_new:
+ **/
+GpkHelperChooser *
+gpk_helper_chooser_new (void)
+{
+	GpkHelperChooser *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_CHOOSER, NULL);
+	return GPK_HELPER_CHOOSER (helper);
+}
+

Added: trunk/src/gpk-helper-chooser.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-chooser.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_CHOOSER_H
+#define __GPK_HELPER_CHOOSER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_CHOOSER		(gpk_helper_chooser_get_type ())
+#define GPK_HELPER_CHOOSER(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooser))
+#define GPK_HELPER_CHOOSER_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass))
+#define GPK_IS_HELPER_CHOOSER(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_CHOOSER))
+#define GPK_IS_HELPER_CHOOSER_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_CHOOSER))
+#define GPK_HELPER_CHOOSER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass))
+#define GPK_HELPER_CHOOSER_ERROR	(gpk_helper_chooser_error_quark ())
+#define GPK_HELPER_CHOOSER_TYPE_ERROR	(gpk_helper_chooser_error_get_type ())
+
+typedef struct GpkHelperChooserPrivate GpkHelperChooserPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperChooserPrivate	*priv;
+} GpkHelperChooser;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperChooser	*helper,
+							 GtkResponseType	 type,
+							 const gchar		*package_id);
+	GObjectClass	parent_class;
+} GpkHelperChooserClass;
+
+GType		 gpk_helper_chooser_get_type	  	(void);
+GpkHelperChooser	*gpk_helper_chooser_new		(void);
+gboolean	 gpk_helper_chooser_set_parent		(GpkHelperChooser	*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_chooser_show		(GpkHelperChooser	*helper,
+							 PkPackageList		*list);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_CHOOSER_H */

Added: trunk/src/gpk-helper-deps-install.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-deps-install.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,198 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+
+#include "gpk-helper-deps-install.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-dialog.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_deps_install_finalize	(GObject	  *object);
+
+#define GPK_HELPER_DEPS_INSTALL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_DEPS_INSTALL, GpkHelperDepsInstallPrivate))
+
+struct GpkHelperDepsInstallPrivate
+{
+	GtkWindow		*window;
+	GConfClient		*gconf_client;
+};
+
+enum {
+	GPK_HELPER_DEPS_INSTALL_EVENT,
+	GPK_HELPER_DEPS_INSTALL_LAST_SIGNAL
+};
+
+static guint signals [GPK_HELPER_DEPS_INSTALL_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperDepsInstall, gpk_helper_deps_install, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_deps_install_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_deps_install_show (GpkHelperDepsInstall *helper, GPtrArray *packages, PkPackageList *deps_list)
+{
+	gchar *name = NULL;
+	gchar *title = NULL;
+	gchar *message = NULL;
+	gchar **package_ids = NULL;
+	guint length;
+	gboolean ret;
+	GtkWidget *dialog;
+	GtkResponseType response;
+
+	/* empty list */
+	length = pk_package_list_get_size (deps_list);
+	if (length == 0) {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_INSTALL_EVENT], 0, GTK_RESPONSE_YES);
+		goto out;
+	}
+
+	/* have we previously said we don't want to be shown the confirmation */
+	ret = gconf_client_get_bool (helper->priv->gconf_client, GPK_CONF_SHOW_DEPENDS, NULL);
+	if (!ret) {
+		egg_debug ("we've said we don't want the dep dialog");
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_INSTALL_EVENT], 0, GTK_RESPONSE_YES);
+		goto out;
+	}
+
+	/* TRANSLATORS: title: tell the user we have to install additional packages */
+	title = g_strdup_printf (ngettext ("%i additional package also has to be installed",
+					   "%i additional packages also have to be installed",
+					   length), length);
+
+	package_ids = pk_ptr_array_to_strv (packages);
+	name = gpk_dialog_package_id_name_join_locale (package_ids);
+
+	/* TRANSLATORS: message: describe in detail why it must happen */
+	message = g_strdup_printf (ngettext ("To install %s, an additional package also has to be downloaded.",
+					     "To install %s, additional packages also have to be downloaded.",
+					     length), name);
+
+	dialog = gtk_message_dialog_new (helper->priv->window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, "%s", title);
+	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
+	gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), deps_list);
+	gpk_dialog_embed_do_not_show_widget (GTK_DIALOG (dialog), GPK_CONF_SHOW_DEPENDS);
+//	gtk_dialog_add_button (GTK_DIALOG (dialog), "help", GTK_RESPONSE_HELP);
+	/* TRANSLATORS: this is button text */
+	gtk_dialog_add_button (GTK_DIALOG (dialog), _("Install"), GTK_RESPONSE_YES);
+
+	/* set icon name */
+	gtk_window_set_icon_name (GTK_WINDOW (dialog), GPK_ICON_SOFTWARE_INSTALLER);
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+
+	/* yes / no */
+	if (response == GTK_RESPONSE_YES) {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_INSTALL_EVENT], 0, response);
+//	} else if (response == GTK_RESPONSE_HELP) {
+//		gpk_gnome_help ("dialog-install-other-packages");
+	} else {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_INSTALL_EVENT], 0, GTK_RESPONSE_NO);
+	}
+out:
+	g_strfreev (package_ids);
+	g_free (name);
+	g_free (title);
+	g_free (message);
+	return TRUE;
+}
+
+/**
+ * gpk_helper_deps_install_set_parent:
+ **/
+gboolean
+gpk_helper_deps_install_set_parent (GpkHelperDepsInstall *helper, GtkWindow *window)
+{
+	g_return_val_if_fail (GPK_IS_HELPER_DEPS_INSTALL (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	helper->priv->window = window;
+	return TRUE;
+}
+
+/**
+ * gpk_helper_deps_install_class_init:
+ * @klass: The GpkHelperDepsInstallClass
+ **/
+static void
+gpk_helper_deps_install_class_init (GpkHelperDepsInstallClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_deps_install_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperDepsInstallPrivate));
+	signals [GPK_HELPER_DEPS_INSTALL_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperDepsInstallClass, event),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+}
+
+/**
+ * gpk_helper_deps_install_init:
+ **/
+static void
+gpk_helper_deps_install_init (GpkHelperDepsInstall *helper)
+{
+	helper->priv = GPK_HELPER_DEPS_INSTALL_GET_PRIVATE (helper);
+	helper->priv->window = NULL;
+	helper->priv->gconf_client = gconf_client_get_default ();
+}
+
+/**
+ * gpk_helper_deps_install_finalize:
+ **/
+static void
+gpk_helper_deps_install_finalize (GObject *object)
+{
+	GpkHelperDepsInstall *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_DEPS_INSTALL (object));
+
+	helper = GPK_HELPER_DEPS_INSTALL (object);
+	g_object_unref (helper->priv->gconf_client);
+
+	G_OBJECT_CLASS (gpk_helper_deps_install_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_deps_install_new:
+ **/
+GpkHelperDepsInstall *
+gpk_helper_deps_install_new (void)
+{
+	GpkHelperDepsInstall *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_DEPS_INSTALL, NULL);
+	return GPK_HELPER_DEPS_INSTALL (helper);
+}
+

Added: trunk/src/gpk-helper-deps-install.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-deps-install.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_DEPS_INSTALL_H
+#define __GPK_HELPER_DEPS_INSTALL_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_DEPS_INSTALL		(gpk_helper_deps_install_get_type ())
+#define GPK_HELPER_DEPS_INSTALL(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_DEPS_INSTALL, GpkHelperDepsInstall))
+#define GPK_HELPER_DEPS_INSTALL_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_DEPS_INSTALL, GpkHelperDepsInstallClass))
+#define GPK_IS_HELPER_DEPS_INSTALL(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_DEPS_INSTALL))
+#define GPK_IS_HELPER_DEPS_INSTALL_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_DEPS_INSTALL))
+#define GPK_HELPER_DEPS_INSTALL_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_DEPS_INSTALL, GpkHelperDepsInstallClass))
+#define GPK_HELPER_DEPS_INSTALL_ERROR		(gpk_helper_deps_install_error_quark ())
+#define GPK_HELPER_DEPS_INSTALL_TYPE_ERROR	(gpk_helper_deps_install_error_get_type ())
+
+typedef struct GpkHelperDepsInstallPrivate GpkHelperDepsInstallPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperDepsInstallPrivate	*priv;
+} GpkHelperDepsInstall;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperDepsInstall	*helper,
+							 GtkResponseType	 type);
+	GObjectClass	parent_class;
+} GpkHelperDepsInstallClass;
+
+GType		 gpk_helper_deps_install_get_type	(void);
+GpkHelperDepsInstall	*gpk_helper_deps_install_new	(void);
+gboolean	 gpk_helper_deps_install_set_parent	(GpkHelperDepsInstall	*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_deps_install_show		(GpkHelperDepsInstall	*helper,
+							 GPtrArray		*packages,
+							 PkPackageList		*deps_list);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_DEPS_INSTALL_H */

Added: trunk/src/gpk-helper-deps-remove.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-deps-remove.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,185 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gpk-helper-deps-remove.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-dialog.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_deps_remove_finalize	(GObject	  *object);
+
+#define GPK_HELPER_DEPS_REMOVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_DEPS_REMOVE, GpkHelperDepsRemovePrivate))
+
+struct GpkHelperDepsRemovePrivate
+{
+	GtkWindow		*window;
+};
+
+enum {
+	GPK_HELPER_DEPS_REMOVE_EVENT,
+	GPK_HELPER_DEPS_REMOVE_LAST_SIGNAL
+};
+
+static guint signals [GPK_HELPER_DEPS_REMOVE_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperDepsRemove, gpk_helper_deps_remove, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_deps_remove_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_deps_remove_show (GpkHelperDepsRemove *helper, GPtrArray *packages, PkPackageList *deps_list)
+{
+	gchar *name = NULL;
+	gchar *title = NULL;
+	gchar *message = NULL;
+	gchar **package_ids = NULL;
+	guint length;
+	GtkWidget *dialog;
+	GtkResponseType response;
+
+	/* empty list */
+	length = pk_package_list_get_size (deps_list);
+	if (length == 0) {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_REMOVE_EVENT], 0, GTK_RESPONSE_YES);
+		goto out;
+	}
+
+	/* TRANSLATORS: title: show the number of other packages we depend on */
+	title = g_strdup_printf (ngettext ("%i additional package also has to be removed",
+					   "%i additional packages also have to be removed",
+					   length), length);
+
+	package_ids = pk_ptr_array_to_strv (packages);
+	name = gpk_dialog_package_id_name_join_locale (package_ids);
+
+	/* TRANSLATORS: message: describe in detail why it must happen */
+	message = g_strdup_printf (ngettext ("To remove %s other packages that depend on it must also be removed.",
+					     "To remove %s other packages that depend on them must also be removed.",
+					     packages->len), name);
+
+	dialog = gtk_message_dialog_new (helper->priv->window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, "%s", title);
+	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
+	gpk_dialog_embed_package_list_widget (GTK_DIALOG (dialog), deps_list);
+
+//	gtk_dialog_add_button (GTK_DIALOG (dialog), "help", GTK_RESPONSE_HELP);
+	/* TRANSLATORS: this is button text */
+	gtk_dialog_add_button (GTK_DIALOG (dialog), _("Remove"), GTK_RESPONSE_YES);
+
+	/* set icon name */
+	gtk_window_set_icon_name (GTK_WINDOW (dialog), GPK_ICON_SOFTWARE_INSTALLER);
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+
+	/* yes / no */
+	if (response == GTK_RESPONSE_YES) {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_REMOVE_EVENT], 0, response);
+//	} else if (response == GTK_RESPONSE_HELP) {
+//		gpk_gnome_help ("dialog-remove-other-packages");
+	} else {
+		g_signal_emit (helper, signals [GPK_HELPER_DEPS_REMOVE_EVENT], 0, GTK_RESPONSE_NO);
+	}
+out:
+	g_strfreev (package_ids);
+	g_free (name);
+	g_free (title);
+	g_free (message);
+	return TRUE;
+}
+
+/**
+ * gpk_helper_deps_remove_set_parent:
+ **/
+gboolean
+gpk_helper_deps_remove_set_parent (GpkHelperDepsRemove *helper, GtkWindow *window)
+{
+	g_return_val_if_fail (GPK_IS_HELPER_DEPS_REMOVE (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	helper->priv->window = window;
+	return TRUE;
+}
+
+/**
+ * gpk_helper_deps_remove_class_init:
+ * @klass: The GpkHelperDepsRemoveClass
+ **/
+static void
+gpk_helper_deps_remove_class_init (GpkHelperDepsRemoveClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_deps_remove_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperDepsRemovePrivate));
+	signals [GPK_HELPER_DEPS_REMOVE_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperDepsRemoveClass, event),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+}
+
+/**
+ * gpk_helper_deps_remove_init:
+ **/
+static void
+gpk_helper_deps_remove_init (GpkHelperDepsRemove *helper)
+{
+	helper->priv = GPK_HELPER_DEPS_REMOVE_GET_PRIVATE (helper);
+	helper->priv->window = NULL;
+}
+
+/**
+ * gpk_helper_deps_remove_finalize:
+ **/
+static void
+gpk_helper_deps_remove_finalize (GObject *object)
+{
+	GpkHelperDepsRemove *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_DEPS_REMOVE (object));
+
+	helper = GPK_HELPER_DEPS_REMOVE (object);
+
+	G_OBJECT_CLASS (gpk_helper_deps_remove_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_deps_remove_new:
+ **/
+GpkHelperDepsRemove *
+gpk_helper_deps_remove_new (void)
+{
+	GpkHelperDepsRemove *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_DEPS_REMOVE, NULL);
+	return GPK_HELPER_DEPS_REMOVE (helper);
+}
+

Added: trunk/src/gpk-helper-deps-remove.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-deps-remove.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_DEPS_REMOVE_H
+#define __GPK_HELPER_DEPS_REMOVE_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_DEPS_REMOVE		(gpk_helper_deps_remove_get_type ())
+#define GPK_HELPER_DEPS_REMOVE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_DEPS_REMOVE, GpkHelperDepsRemove))
+#define GPK_HELPER_DEPS_REMOVE_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_DEPS_REMOVE, GpkHelperDepsRemoveClass))
+#define GPK_IS_HELPER_DEPS_REMOVE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_DEPS_REMOVE))
+#define GPK_IS_HELPER_DEPS_REMOVE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_DEPS_REMOVE))
+#define GPK_HELPER_DEPS_REMOVE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_DEPS_REMOVE, GpkHelperDepsRemoveClass))
+#define GPK_HELPER_DEPS_REMOVE_ERROR		(gpk_helper_deps_remove_error_quark ())
+#define GPK_HELPER_DEPS_REMOVE_TYPE_ERROR	(gpk_helper_deps_remove_error_get_type ())
+
+typedef struct GpkHelperDepsRemovePrivate GpkHelperDepsRemovePrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperDepsRemovePrivate	*priv;
+} GpkHelperDepsRemove;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperDepsRemove	*helper,
+							 GtkResponseType	 type);
+	GObjectClass	parent_class;
+} GpkHelperDepsRemoveClass;
+
+GType		 gpk_helper_deps_remove_get_type	(void);
+GpkHelperDepsRemove	*gpk_helper_deps_remove_new	(void);
+gboolean	 gpk_helper_deps_remove_set_parent	(GpkHelperDepsRemove	*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_deps_remove_show		(GpkHelperDepsRemove	*helper,
+							 GPtrArray		*packages,
+							 PkPackageList		*deps_list);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_DEPS_REMOVE_H */

Modified: trunk/src/gpk-helper-eula.c
==============================================================================
--- trunk/src/gpk-helper-eula.c	(original)
+++ trunk/src/gpk-helper-eula.c	Tue Apr 14 16:28:59 2009
@@ -133,17 +133,18 @@
 gboolean
 gpk_helper_eula_set_parent (GpkHelperEula *helper, GtkWindow *window)
 {
-	GtkWidget *widget;
+	GtkWindow *widget;
 
 	g_return_val_if_fail (GPK_IS_HELPER_EULA (helper), FALSE);
 	g_return_val_if_fail (window != NULL, FALSE);
 
 	/* make modal if window set */
-	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_eula"));
-	gtk_window_set_transient_for (GTK_WINDOW (widget), window);
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_eula"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
 
 	/* this is a modal popup, so don't show a window title */
-	gtk_window_set_title (GTK_WINDOW (widget), "");
+	gtk_window_set_title (widget, "");
 
 	return TRUE;
 }

Added: trunk/src/gpk-helper-media-change.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-media-change.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,187 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gpk-helper-media-change.h"
+#include "gpk-enum.h"
+#include "gpk-common.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_media_change_finalize	(GObject	  *object);
+
+#define GPK_HELPER_MEDIA_CHANGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_MEDIA_CHANGE, GpkHelperMediaChangePrivate))
+
+struct GpkHelperMediaChangePrivate
+{
+	GtkWindow		*window;
+	guint			 idle_id;
+	PkMediaTypeEnum		 type;
+	gchar			*media_id;
+	gchar			*media_text;
+};
+
+enum {
+	GPK_HELPER_MEDIA_CHANGE_EVENT,
+	GPK_HELPER_MEDIA_CHANGE_LAST_SIGNAL
+};
+
+static guint signals [GPK_HELPER_MEDIA_CHANGE_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperMediaChange, gpk_helper_media_change, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_media_change_show_idle_cb:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_media_change_show_idle_cb (GpkHelperMediaChange *helper)
+{
+	const gchar *name = NULL;
+	gchar *message = NULL;
+	GtkWidget *dialog;
+	GtkResponseType response;
+
+	name = gpk_media_type_enum_to_localised_text (helper->priv->type);
+	/* TRANSLATORS: dialog body, explains to the user that they need to insert a disk to continue. The first replacement is DVD, CD etc */
+	message = g_strdup_printf (_("Additional media is required. Please insert the %s labeled '%s' and click continue"), name, helper->priv->media_text);
+
+	dialog = gtk_message_dialog_new (helper->priv->window, GTK_DIALOG_DESTROY_WITH_PARENT,
+					 /* TRANSLATORS: this is the window title when a new cd or dvd is required */
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, _("A media change is required"));
+	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message);
+
+	/* TRANSLATORS: this is button text */
+	gtk_dialog_add_button (GTK_DIALOG (dialog), _("Continue"), GTK_RESPONSE_YES);
+
+	/* set icon name */
+	gtk_window_set_icon_name (GTK_WINDOW (dialog), GPK_ICON_SOFTWARE_INSTALLER);
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+
+	/* yes / no */
+	if (response == GTK_RESPONSE_YES) {
+		g_signal_emit (helper, signals [GPK_HELPER_MEDIA_CHANGE_EVENT], 0, response);
+	} else {
+		g_signal_emit (helper, signals [GPK_HELPER_MEDIA_CHANGE_EVENT], 0, GTK_RESPONSE_NO);
+	}
+	g_free (message);
+
+	/* never repeat */
+	helper->priv->media_id = 0;
+	return FALSE;
+}
+
+/**
+ * gpk_helper_media_change_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_media_change_show (GpkHelperMediaChange *helper, PkMediaTypeEnum type, const gchar *media_id, const gchar *media_text)
+{
+	g_return_val_if_fail (GPK_IS_HELPER_MEDIA_CHANGE (helper), FALSE);
+	g_return_val_if_fail (helper->priv->media_id == 0, FALSE);
+
+	helper->priv->type = type;
+	helper->priv->media_id = g_strdup (media_id);
+	helper->priv->media_text = g_strdup (media_text);
+	helper->priv->idle_id = g_idle_add ((GSourceFunc) gpk_helper_media_change_show_idle_cb, helper);
+	return TRUE;
+}
+
+/**
+ * gpk_helper_media_change_set_parent:
+ **/
+gboolean
+gpk_helper_media_change_set_parent (GpkHelperMediaChange *helper, GtkWindow *window)
+{
+	g_return_val_if_fail (GPK_IS_HELPER_MEDIA_CHANGE (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	helper->priv->window = window;
+	return TRUE;
+}
+
+/**
+ * gpk_helper_media_change_class_init:
+ * @klass: The GpkHelperMediaChangeClass
+ **/
+static void
+gpk_helper_media_change_class_init (GpkHelperMediaChangeClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_media_change_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperMediaChangePrivate));
+	signals [GPK_HELPER_MEDIA_CHANGE_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperMediaChangeClass, event),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+}
+
+/**
+ * gpk_helper_media_change_init:
+ **/
+static void
+gpk_helper_media_change_init (GpkHelperMediaChange *helper)
+{
+	helper->priv = GPK_HELPER_MEDIA_CHANGE_GET_PRIVATE (helper);
+	helper->priv->window = NULL;
+	helper->priv->idle_id = 0;
+}
+
+/**
+ * gpk_helper_media_change_finalize:
+ **/
+static void
+gpk_helper_media_change_finalize (GObject *object)
+{
+	GpkHelperMediaChange *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_MEDIA_CHANGE (object));
+
+	helper = GPK_HELPER_MEDIA_CHANGE (object);
+	if (helper->priv->idle_id != 0)
+		g_source_remove (helper->priv->idle_id);
+	g_free (helper->priv->media_id);
+	g_free (helper->priv->media_text);
+
+	G_OBJECT_CLASS (gpk_helper_media_change_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_media_change_new:
+ **/
+GpkHelperMediaChange *
+gpk_helper_media_change_new (void)
+{
+	GpkHelperMediaChange *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_MEDIA_CHANGE, NULL);
+	return GPK_HELPER_MEDIA_CHANGE (helper);
+}
+

Added: trunk/src/gpk-helper-media-change.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-media-change.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_MEDIA_CHANGE_H
+#define __GPK_HELPER_MEDIA_CHANGE_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_MEDIA_CHANGE		(gpk_helper_media_change_get_type ())
+#define GPK_HELPER_MEDIA_CHANGE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_MEDIA_CHANGE, GpkHelperMediaChange))
+#define GPK_HELPER_MEDIA_CHANGE_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_MEDIA_CHANGE, GpkHelperMediaChangeClass))
+#define GPK_IS_HELPER_MEDIA_CHANGE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_MEDIA_CHANGE))
+#define GPK_IS_HELPER_MEDIA_CHANGE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_MEDIA_CHANGE))
+#define GPK_HELPER_MEDIA_CHANGE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_MEDIA_CHANGE, GpkHelperMediaChangeClass))
+#define GPK_HELPER_MEDIA_CHANGE_ERROR		(gpk_helper_media_change_error_quark ())
+#define GPK_HELPER_MEDIA_CHANGE_TYPE_ERROR	(gpk_helper_media_change_error_get_type ())
+
+typedef struct GpkHelperMediaChangePrivate GpkHelperMediaChangePrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperMediaChangePrivate	*priv;
+} GpkHelperMediaChange;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperMediaChange	*helper,
+							 GtkResponseType	 type);
+	GObjectClass	parent_class;
+} GpkHelperMediaChangeClass;
+
+GType			 gpk_helper_media_change_get_type	(void);
+GpkHelperMediaChange	*gpk_helper_media_change_new		(void);
+gboolean		 gpk_helper_media_change_set_parent	(GpkHelperMediaChange	*helper,
+								 GtkWindow		*window);
+gboolean		 gpk_helper_media_change_show		(GpkHelperMediaChange	*helper,
+								 PkMediaTypeEnum	 type,
+								 const gchar		*media_id,
+								 const gchar		*media_text);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_MEDIA_CHANGE_H */

Modified: trunk/src/gpk-helper-repo-signature.c
==============================================================================
--- trunk/src/gpk-helper-repo-signature.c	(original)
+++ trunk/src/gpk-helper-repo-signature.c	Tue Apr 14 16:28:59 2009
@@ -128,17 +128,18 @@
 gboolean
 gpk_helper_repo_signature_set_parent (GpkHelperRepoSignature *helper, GtkWindow *window)
 {
-	GtkWidget *widget;
+	GtkWindow *widget;
 
 	g_return_val_if_fail (GPK_IS_HELPER_REPO_SIGNATURE (helper), FALSE);
 	g_return_val_if_fail (window != NULL, FALSE);
 
 	/* make modal if window set */
-	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_gpg"));
-	gtk_window_set_transient_for (GTK_WINDOW (widget), window);
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_gpg"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
 
 	/* this is a modal popup, so don't show a window title */
-	gtk_window_set_title (GTK_WINDOW (widget), "");
+	gtk_window_set_title (widget, "");
 
 	return TRUE;
 }

Added: trunk/src/gpk-helper-run.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-run.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,530 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+#include "gpk-helper-run.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-desktop.h"
+#include "gpk-enum.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_run_finalize	(GObject	  *object);
+
+#define GPK_HELPER_RUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunPrivate))
+
+struct GpkHelperRunPrivate
+{
+	GtkBuilder		*builder;
+	GtkListStore		*list_store;
+	gchar			*full_path;
+};
+
+enum {
+	GPK_CHOOSER_COLUMN_ICON,
+	GPK_CHOOSER_COLUMN_TEXT,
+	GPK_CHOOSER_COLUMN_FULL_PATH,
+	GPK_CHOOSER_COLUMN_LAST
+};
+
+G_DEFINE_TYPE (GpkHelperRun, gpk_helper_run, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_run_path:
+ **/
+static gboolean
+gpk_helper_run_path (GpkHelperRun *helper)
+{
+	gboolean ret = FALSE;
+	GError *error = NULL;
+
+	/* check have value */
+	if (helper->priv->full_path == NULL) {
+		egg_warning ("no full path");
+		goto out;
+	}
+
+	ret = g_spawn_command_line_async (helper->priv->full_path, &error);
+	if (!ret) {
+		egg_warning ("failed to run: %s", error->message);
+		g_error_free (error);
+	}
+out:
+	return ret;
+}
+
+/**
+ * gpk_helper_run_button_run_cb:
+ **/
+static void
+gpk_helper_run_button_run_cb (GtkWidget *widget, GpkHelperRun *helper)
+{
+	gpk_helper_run_path (helper);
+}
+
+/**
+ * gpk_helper_run_button_close_cb:
+ **/
+static void
+gpk_helper_run_button_close_cb (GtkWidget *widget, GpkHelperRun *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_helper_run_button_help_cb:
+ **/
+static void
+gpk_helper_run_button_help_cb (GtkWidget *widget, GpkHelperRun *helper)
+{
+	/* show the help */
+	gpk_gnome_help ("run");
+}
+
+/**
+ * gpk_helper_run_delete_event_cb:
+ **/
+static gboolean
+gpk_helper_run_delete_event_cb (GtkWidget *widget, GdkEvent *event, GpkHelperRun *helper)
+{
+	/* clear full_path */
+	g_free (helper->priv->full_path);
+	helper->priv->full_path = NULL;
+
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	return FALSE;
+}
+
+
+/**
+ * gpk_helper_run_treeview_clicked_cb:
+ **/
+static void
+gpk_helper_run_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperRun *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	/* This will only work in single or browse selection mode! */
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		g_free (helper->priv->full_path);
+		gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FULL_PATH, &helper->priv->full_path, -1);
+
+		/* show full path */
+		egg_debug ("selected row is: %s", helper->priv->full_path);
+	} else {
+		egg_debug ("no row selected");
+	}
+}
+
+/**
+ * gpk_helper_run_row_activated_cb:
+ **/
+static void
+gpk_helper_run_row_activated_cb (GtkTreeView *treeview, GtkTreePath *path,
+				 GtkTreeViewColumn *col, GpkHelperRun *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean ret;
+
+	/* get selection */
+	model = gtk_tree_view_get_model (treeview);
+	ret = gtk_tree_model_get_iter (model, &iter, path);
+	if (!ret) {
+		egg_warning ("failed to get selection");
+		return;
+	}
+
+	g_free (helper->priv->full_path);
+	gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FULL_PATH, &helper->priv->full_path, -1);
+	gpk_helper_run_path (helper);
+}
+
+/**
+ * pk_treeview_add_general_columns:
+ **/
+static void
+pk_treeview_add_general_columns (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* image */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+        g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+	/* TRANSLATORS: column for the application icon */
+	column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer,
+							   "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the package name */
+	column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer,
+							   "markup", GPK_CHOOSER_COLUMN_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+	gtk_tree_view_column_set_expand (column, TRUE);
+}
+
+/**
+ * gpk_helper_run_add_desktop_file:
+ **/
+static gboolean
+gpk_helper_run_add_desktop_file (GpkHelperRun *helper, const gchar *package_id, const gchar *filename)
+{
+	gboolean ret;
+	gchar *icon = NULL;
+	gchar *text = NULL;
+	gchar *fulltext = NULL;
+	gchar *name = NULL;
+	gchar *exec = NULL;
+	gchar *summary = NULL;
+	gchar *joint = NULL;
+	gchar *menu_path = NULL;
+	GtkTreeIter iter;
+	GKeyFile *file;
+	PkPackageId *id;
+	gint weight;
+
+	/* get weight */
+	weight = gpk_desktop_get_file_weight (filename);
+	if (weight < 0) {
+		egg_debug ("ignoring %s", filename);
+		goto out;
+	}
+
+	/* get some data from the desktop file */
+	file = g_key_file_new ();
+	ret = g_key_file_load_from_file (file, filename, G_KEY_FILE_NONE, NULL);
+	if (!ret) {
+		egg_debug ("failed to load %s", filename);
+		goto out;
+	}
+
+	/* get exec */
+	exec = g_key_file_get_string (file, G_KEY_FILE_DESKTOP_GROUP, "TryExec", NULL);
+	if (exec == NULL)
+		exec = g_key_file_get_string (file, G_KEY_FILE_DESKTOP_GROUP, "Exec", NULL);
+
+	/* abandon attempt */
+	if (exec == NULL) {
+		ret = FALSE;
+		goto out;
+	}
+
+	/* get name */
+	text = g_key_file_get_locale_string (file, G_KEY_FILE_DESKTOP_GROUP, "Name", NULL, NULL);
+	if (text != NULL)
+		name = g_markup_escape_text (text, -1);
+	g_free (text);
+
+	/* get icon */
+	icon = g_key_file_get_string (file, G_KEY_FILE_DESKTOP_GROUP, "Icon", NULL);
+	if (icon == NULL || !gpk_desktop_check_icon_valid (icon)) {
+		g_free (icon);
+		icon = g_strdup (gpk_info_enum_to_icon_name (PK_INFO_ENUM_AVAILABLE));
+	}
+
+	/* get summary */
+	text = g_key_file_get_locale_string (file, G_KEY_FILE_DESKTOP_GROUP, "Comment", NULL, NULL);
+	if (text == NULL)
+		text = g_key_file_get_locale_string (file, G_KEY_FILE_DESKTOP_GROUP, "GenericName", NULL, NULL);
+	if (text != NULL)
+		summary = g_markup_escape_text (text, -1);
+	g_free (text);
+
+	/* get application path */
+	text = gpk_desktop_get_menu_path (filename);
+	if (text != NULL)
+		menu_path = g_markup_escape_text (text, -1);
+	g_free (text);
+
+	/* put formatted text into treeview */
+	gtk_list_store_append (helper->priv->list_store, &iter);
+	joint = g_strdup_printf ("%s - %s", name, summary);
+	id = pk_package_id_new_from_string (package_id);
+	text = gpk_package_id_format_twoline (id, joint);
+	if (menu_path != NULL) {
+		/* TRANSLATORS: the path in the menu, e.g. Applications -> Games -> Dave */
+		fulltext = g_strdup_printf("%s\n\n<i>%s</i>", text, menu_path);
+		g_free (text);
+		text = fulltext;
+	}
+	pk_package_id_free (id);
+
+	gtk_list_store_set (helper->priv->list_store, &iter,
+			    GPK_CHOOSER_COLUMN_TEXT, fulltext,
+			    GPK_CHOOSER_COLUMN_FULL_PATH, exec,
+			    GPK_CHOOSER_COLUMN_ICON, icon, -1);
+out:
+	if (file != NULL)
+		g_key_file_free (file);
+	g_free (exec);
+	g_free (icon);
+	g_free (name);
+	g_free (text);
+	g_free (menu_path);
+	g_free (joint);
+	g_free (summary);
+
+	return ret;
+}
+
+/**
+ * gpk_helper_run_add_package_ids:
+ **/
+static guint
+gpk_helper_run_add_package_ids (GpkHelperRun *helper, gchar **package_ids)
+{
+	guint i, j;
+	guint length;
+	guint added = 0;
+	const gchar *filename;
+	GPtrArray *array;
+	gchar **parts;
+	gboolean ret;
+	PkDesktop *desktop;
+
+	/* open database */
+	desktop = pk_desktop_new ();
+	ret = pk_desktop_open_database (desktop, NULL);
+	if (!ret) {
+		egg_debug ("failed to open desktop DB");
+		goto out;
+	}
+
+	/* add each package */
+	length = g_strv_length (package_ids);
+	for (i=0; i<length; i++) {
+		parts = g_strsplit (package_ids[i], ";", 0);
+		array = pk_desktop_get_files_for_package (desktop, parts[0], NULL);
+		if (array != NULL) {
+			for (j=0; j<array->len; j++) {
+				filename = g_ptr_array_index (array, j);
+				ret = gpk_helper_run_add_desktop_file (helper, package_ids[i], filename);
+				if (ret)
+					added++;
+			}
+			g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+			g_ptr_array_free (array, TRUE);
+		}
+		g_strfreev (parts);
+	}
+	g_object_unref (desktop);
+out:
+	return added;
+}
+
+/**
+ * gpk_helper_run_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_run_show (GpkHelperRun *helper, gchar **package_ids)
+{
+	GtkWidget *widget;
+	guint len;
+
+	g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE);
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* clear old list */
+	gtk_list_store_clear (helper->priv->list_store);
+
+	/* add all the apps */
+	len = gpk_helper_run_add_package_ids (helper, package_ids);
+	if (len == 0) {
+		egg_debug ("no executable file for %s", package_ids[0]);
+		goto out;
+	}
+
+	/* show window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_show (widget);
+out:
+	return TRUE;
+}
+
+/**
+ * gpk_helper_run_set_parent:
+ **/
+gboolean
+gpk_helper_run_set_parent (GpkHelperRun *helper, GtkWindow *window)
+{
+	GtkWindow *widget;
+
+	g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (widget, "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_run_class_init:
+ * @klass: The GpkHelperRunClass
+ **/
+static void
+gpk_helper_run_class_init (GpkHelperRunClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_run_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperRunPrivate));
+}
+
+/**
+ * gpk_helper_run_init:
+ **/
+static void
+gpk_helper_run_init (GpkHelperRun *helper)
+{
+	GtkWidget *widget;
+	GtkWidget *button;
+	guint retval;
+	GError *error = NULL;
+	GtkTreeSelection *selection;
+	GtkBox *box;
+
+	helper->priv = GPK_HELPER_RUN_GET_PRIVATE (helper);
+
+	/* initially nothing */
+	helper->priv->full_path = NULL;
+
+	/* get UI */
+	helper->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error);
+	if (error != NULL) {
+		egg_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* connect up default actions */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_helper_run_delete_event_cb), helper);
+
+	/* set icon name */
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+
+	/* set a size, if the screen allows */
+	gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300);
+
+	/* connect up buttons */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_run_button_close_cb), helper);
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_help"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_run_button_help_cb), helper);
+
+	/* hide the filter box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter"));
+	gtk_widget_hide (widget);
+
+	/* hide the refresh button */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh"));
+	gtk_widget_hide (widget);
+
+	/* set icon name */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+	/* TRANSLATORS: window title: do we want to execute a program we just installed? */
+	gtk_window_set_title (GTK_WINDOW (widget), _("Run new application?"));
+
+	/* add run button */
+	button = gtk_button_new_with_mnemonic (_("_Run"));
+	box = GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (widget)));
+	gtk_box_pack_start (box, button, FALSE, FALSE, 0);
+	gtk_widget_show (button);
+	g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_run_button_run_cb), helper);
+
+	/* create list stores */
+	helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* create package_id tree view */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple"));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (helper->priv->list_store));
+	g_signal_connect (GTK_TREE_VIEW (widget), "row-activated",
+			  G_CALLBACK (gpk_helper_run_row_activated_cb), helper);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	g_signal_connect (selection, "changed",
+			  G_CALLBACK (gpk_helper_run_treeview_clicked_cb), helper);
+
+	/* add columns to the tree view */
+	pk_treeview_add_general_columns (GTK_TREE_VIEW (widget));
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+}
+
+/**
+ * gpk_helper_run_finalize:
+ **/
+static void
+gpk_helper_run_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkHelperRun *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_RUN (object));
+
+	helper = GPK_HELPER_RUN (object);
+
+	/* hide window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_free (helper->priv->full_path);
+	g_object_unref (helper->priv->builder);
+	g_object_unref (helper->priv->list_store);
+
+	G_OBJECT_CLASS (gpk_helper_run_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_run_new:
+ **/
+GpkHelperRun *
+gpk_helper_run_new (void)
+{
+	GpkHelperRun *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_RUN, NULL);
+	return GPK_HELPER_RUN (helper);
+}
+

Added: trunk/src/gpk-helper-run.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-run.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_RUN_H
+#define __GPK_HELPER_RUN_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_RUN		(gpk_helper_run_get_type ())
+#define GPK_HELPER_RUN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_RUN, GpkHelperRun))
+#define GPK_HELPER_RUN_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_RUN, GpkHelperRunClass))
+#define GPK_IS_HELPER_RUN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_RUN))
+#define GPK_IS_HELPER_RUN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_RUN))
+#define GPK_HELPER_RUN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunClass))
+#define GPK_HELPER_RUN_ERROR		(gpk_helper_run_error_quark ())
+#define GPK_HELPER_RUN_TYPE_ERROR	(gpk_helper_run_error_get_type ())
+
+typedef struct GpkHelperRunPrivate GpkHelperRunPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperRunPrivate		*priv;
+} GpkHelperRun;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} GpkHelperRunClass;
+
+GType		 gpk_helper_run_get_type	  	(void);
+GpkHelperRun	*gpk_helper_run_new			(void);
+gboolean	 gpk_helper_run_set_parent		(GpkHelperRun		*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_run_show			(GpkHelperRun		*helper,
+							 gchar			**package_ids);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_RUN_H */

Added: trunk/src/gpk-helper-untrusted.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-untrusted.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,240 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gpk-helper-untrusted.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-enum.h"
+
+#include "egg-debug.h"
+
+static void     gpk_helper_untrusted_finalize	(GObject	  *object);
+
+#define GPK_HELPER_UNTRUSTED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_UNTRUSTED, GpkHelperUntrustedPrivate))
+
+struct GpkHelperUntrustedPrivate
+{
+	GtkBuilder		*builder;
+};
+
+enum {
+	GPK_HELPER_UNTRUSTED_EVENT,
+	GPK_HELPER_UNTRUSTED_LAST_SIGNAL
+};
+
+static guint signals [GPK_HELPER_UNTRUSTED_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperUntrusted, gpk_helper_untrusted, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_untrusted_button_force_install_cb:
+ **/
+static void
+gpk_helper_untrusted_button_force_install_cb (GtkWidget *widget, GpkHelperUntrusted *helper)
+{
+	g_signal_emit (helper, signals [GPK_HELPER_UNTRUSTED_EVENT], 0, GTK_RESPONSE_YES);
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_helper_untrusted_button_cancel_cb:
+ **/
+static void
+gpk_helper_untrusted_button_cancel_cb (GtkWidget *widget, GpkHelperUntrusted *helper)
+{
+	g_signal_emit (helper, signals [GPK_HELPER_UNTRUSTED_EVENT], 0, GTK_RESPONSE_NO);
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_helper_untrusted_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_untrusted_show (GpkHelperUntrusted *helper, PkErrorCodeEnum code)
+{
+	GtkWidget *widget;
+	gchar *text;
+	const gchar *title;
+	gchar *message;
+
+	g_return_val_if_fail (GPK_IS_HELPER_UNTRUSTED (helper), FALSE);
+
+	/* title */
+	title = gpk_error_enum_to_localised_text (code);
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "label_title"));
+	text = g_strdup_printf ("<b><big>%s</big></b>", title);
+	gtk_label_set_label (GTK_LABEL (widget), text);
+	g_free (text);
+
+	/* message */
+	message = g_strdup_printf ("%s\n%s\n\n%s\n%s",
+				   /* TRANSLATORS: is not GPG signed */
+				   _("The package is not signed by a trusted provider."),
+				   /* TRANSLATORS: user has to trust provider -- I know, this sucks */
+				   _("Do not install this package unless you are sure it is safe to do so."),
+				   /* TRANSLATORS: warn the user that all bets are off */
+				   _("Malicious software can damage your computer or cause other harm."),
+				   /* TRANSLATORS: ask if they are absolutely sure they want to do this */
+				   _("Are you <b>sure</b> you want to install this package?"));
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "label_message"));
+	gtk_label_set_markup (GTK_LABEL (widget), message);
+	g_free (message);
+
+	/* show window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	gtk_widget_show (widget);
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_untrusted_set_parent:
+ **/
+gboolean
+gpk_helper_untrusted_set_parent (GpkHelperUntrusted *helper, GtkWindow *window)
+{
+	GtkWindow *widget;
+
+	g_return_val_if_fail (GPK_IS_HELPER_UNTRUSTED (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (widget, "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_untrusted_class_init:
+ * @klass: The GpkHelperUntrustedClass
+ **/
+static void
+gpk_helper_untrusted_class_init (GpkHelperUntrustedClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_untrusted_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperUntrustedPrivate));
+	signals [GPK_HELPER_UNTRUSTED_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperUntrustedClass, event),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+}
+
+/**
+ * gpk_helper_untrusted_init:
+ **/
+static void
+gpk_helper_untrusted_init (GpkHelperUntrusted *helper)
+{
+	GtkWidget *widget;
+	GtkWidget *button;
+	guint retval;
+	GError *error = NULL;
+
+	helper->priv = GPK_HELPER_UNTRUSTED_GET_PRIVATE (helper);
+
+	/* get UI */
+	helper->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-error.ui", &error);
+	if (error != NULL) {
+		egg_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* connect up default actions */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_helper_untrusted_button_cancel_cb), helper);
+
+	/* set icon name */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+
+	/* connect up buttons */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_untrusted_button_cancel_cb), helper);
+
+	/* don't show text in the expander */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "expander_details"));
+	gtk_widget_hide (widget);
+
+	/* TRANSLATORS: button label, force the install, even though it's untrusted */
+	button = gtk_button_new_with_mnemonic (_("_Force install"));
+	g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_untrusted_button_force_install_cb), helper);
+
+	/* TRANSLATORS: button tooltip */
+	gtk_widget_set_tooltip_text (button, _("Force installing package"));
+
+	/* add to box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	widget = gtk_dialog_get_action_area (GTK_DIALOG(widget));
+	gtk_box_pack_start (GTK_BOX (widget), button, FALSE, FALSE, 0);
+	gtk_widget_show (button);
+}
+
+/**
+ * gpk_helper_untrusted_finalize:
+ **/
+static void
+gpk_helper_untrusted_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkHelperUntrusted *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_UNTRUSTED (object));
+
+	helper = GPK_HELPER_UNTRUSTED (object);
+
+	/* hide window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_error"));
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_object_unref (helper->priv->builder);
+
+	G_OBJECT_CLASS (gpk_helper_untrusted_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_untrusted_new:
+ **/
+GpkHelperUntrusted *
+gpk_helper_untrusted_new (void)
+{
+	GpkHelperUntrusted *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_UNTRUSTED, NULL);
+	return GPK_HELPER_UNTRUSTED (helper);
+}
+

Added: trunk/src/gpk-helper-untrusted.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-helper-untrusted.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard 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 __GPK_HELPER_UNTRUSTED_H
+#define __GPK_HELPER_UNTRUSTED_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_UNTRUSTED		(gpk_helper_untrusted_get_type ())
+#define GPK_HELPER_UNTRUSTED(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_UNTRUSTED, GpkHelperUntrusted))
+#define GPK_HELPER_UNTRUSTED_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_UNTRUSTED, GpkHelperUntrustedClass))
+#define GPK_IS_HELPER_UNTRUSTED(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_UNTRUSTED))
+#define GPK_IS_HELPER_UNTRUSTED_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_UNTRUSTED))
+#define GPK_HELPER_UNTRUSTED_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_UNTRUSTED, GpkHelperUntrustedClass))
+#define GPK_HELPER_UNTRUSTED_ERROR		(gpk_helper_untrusted_error_quark ())
+#define GPK_HELPER_UNTRUSTED_TYPE_ERROR		(gpk_helper_untrusted_error_get_type ())
+
+typedef struct GpkHelperUntrustedPrivate GpkHelperUntrustedPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperUntrustedPrivate	*priv;
+} GpkHelperUntrusted;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperUntrusted	*helper,
+							 GtkResponseType	 type);
+	GObjectClass	parent_class;
+} GpkHelperUntrustedClass;
+
+GType			 gpk_helper_untrusted_get_type	  	(void);
+GpkHelperUntrusted	*gpk_helper_untrusted_new		(void);
+gboolean		 gpk_helper_untrusted_set_parent	(GpkHelperUntrusted	*helper,
+								 GtkWindow		*window);
+gboolean		 gpk_helper_untrusted_show		(GpkHelperUntrusted	*helper,
+								 PkErrorCodeEnum	 code);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_UNTRUSTED_H */

Modified: trunk/src/gpk-install-catalog.c
==============================================================================
--- trunk/src/gpk-install-catalog.c	(original)
+++ trunk/src/gpk-install-catalog.c	Tue Apr 14 16:28:59 2009
@@ -26,12 +26,12 @@
 #include <gtk/gtk.h>
 #include <locale.h>
 #include <packagekit-glib/packagekit.h>
+#include <dbus/dbus-glib.h>
 
 #include "egg-debug.h"
 
 #include "gpk-common.h"
 #include "gpk-error.h"
-#include "gpk-client.h"
 
 /**
  * main:
@@ -40,7 +40,9 @@
 main (int argc, char *argv[])
 {
 	GOptionContext *context;
-	GpkClient *gclient;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
+	GError *error = NULL;
 	gboolean ret;
 	gboolean verbose = FALSE;
 	gchar **files = NULL;
@@ -78,24 +80,52 @@
 	/* are we running privileged */
 	ret = gpk_check_privileged_user (_("Catalog installer"), TRUE);
 	if (!ret)
-		return 1;
+		goto out;
 
 	if (files == NULL) {
 		gpk_error_dialog (_("Failed to install catalog"),
 				  /* TRANSLATORS: no filename was supplied */
 				  _("You need to specify a file name to install"), NULL);
-		return 1;
+		goto out;
 	}
 
-	/* find the file list */
-	gclient = gpk_client_new ();
-	gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	/* install all the catalogs */
-	ret = gpk_client_install_catalogs (gclient, files, NULL);
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
 
-	g_object_unref (gclient);
-	g_strfreev (files);
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		egg_warning ("Cannot connect to session service");
+		goto out;
+	}
 
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallCatalogs", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, files, /* data */
+				 G_TYPE_STRING, "", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (files);
 	return !ret;
 }
 

Modified: trunk/src/gpk-install-local-file.c
==============================================================================
--- trunk/src/gpk-install-local-file.c	(original)
+++ trunk/src/gpk-install-local-file.c	Tue Apr 14 16:28:59 2009
@@ -25,11 +25,11 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <locale.h>
+#include <dbus/dbus-glib.h>
 
 #include "egg-debug.h"
 
 #include "gpk-common.h"
-#include "gpk-client.h"
 #include "gpk-error.h"
 
 /**
@@ -41,9 +41,10 @@
 	GOptionContext *context;
 	gboolean ret;
 	gboolean verbose = FALSE;
-	GError *error;
-	GpkClient *gclient;
+	GError *error = NULL;
 	gchar **files = NULL;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
 
 	const GOptionEntry options[] = {
 		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
@@ -78,22 +79,52 @@
 	/* TRANSLATORS: title to pass to to the user if there are not enough privs */
 	ret = gpk_check_privileged_user (_("Local file installer"), TRUE);
 	if (!ret)
-		return 1;
+		goto out;
 
 	if (files == NULL) {
 		/* TRANSLATORS: could not install a package that contained the file we wanted */
 		gpk_error_dialog (_("Failed to install a package to provide a file"),
 				  /* TRANSLATORS: nothing selected */
 				  _("You need to specify a file to install"), NULL);
-		return 1;
+		goto out;
 	}
 
-	error = NULL;
-	gclient = gpk_client_new ();
-	gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	ret = gpk_client_install_local_files (gclient, files, NULL);
-	g_strfreev (files);
-	g_object_unref (gclient);
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		egg_warning ("Cannot connect to session service");
+		goto out;
+	}
 
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallPackageFiles", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, files, /* data */
+				 G_TYPE_STRING, "hide-finished", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (files);
 	return !ret;
 }

Modified: trunk/src/gpk-install-mime-type.c
==============================================================================
--- trunk/src/gpk-install-mime-type.c	(original)
+++ trunk/src/gpk-install-mime-type.c	Tue Apr 14 16:28:59 2009
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2008 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2008-2009 Richard Hughes <richard hughsie com>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -25,11 +25,11 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <locale.h>
+#include <dbus/dbus-glib.h>
 
 #include "egg-debug.h"
 
 #include "gpk-common.h"
-#include "gpk-client.h"
 #include "gpk-error.h"
 
 /**
@@ -41,12 +41,17 @@
 	GOptionContext *context;
 	gboolean ret;
 	gboolean verbose = FALSE;
-	GError *error;
-	GpkClient *gclient;
+	GError *error = NULL;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
+	gchar **types = NULL;
 
 	const GOptionEntry options[] = {
 		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
 		  _("Show extra debugging information"), NULL },
+		{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &types,
+		/* TRANSLATORS: command line option: a list of catalogs to install */
+		  _("Mime types to install"), NULL },
 		{ NULL}
 	};
 
@@ -74,28 +79,52 @@
 	/* TRANSLATORS: title to pass to to the user if there are not enough privs */
 	ret = gpk_check_privileged_user (_("Mime type installer"), TRUE);
 	if (!ret)
-		return 1;
+		goto out;
 
-	if (argc < 2) {
+	if (types == NULL) {
 		/* TRANSLATORS: could not install program supporting this type */
 		gpk_error_dialog (_("Failed to install a program to handle this file type"),
 				  /* TRANSLATORS: no type given */
 				  _("You need to specify a mime-type to install"), NULL);
-		return 1;
+		goto out;
 	}
-	if (argc > 2) {
-		/* TRANSLATORS: could not install program supporting this type */
-		gpk_error_dialog (_("Failed to install a program to handle this file type"),
-				  /* TRANSLATORS: more than one type given */
-				  _("You can only specify one mime-type to install"), NULL);
-		return 1;
+
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
 	}
 
-	error = NULL;
-	gclient = gpk_client_new ();
-	gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	ret = gpk_client_install_mime_type (gclient, argv[1], NULL);
-	g_object_unref (gclient);
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		egg_warning ("Cannot connect to session service");
+		goto out;
+	}
+
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
 
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallMimeTypes", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, types, /* data */
+				 G_TYPE_STRING, "", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (types);
 	return !ret;
 }

Modified: trunk/src/gpk-install-package-name.c
==============================================================================
--- trunk/src/gpk-install-package-name.c	(original)
+++ trunk/src/gpk-install-package-name.c	Tue Apr 14 16:28:59 2009
@@ -25,11 +25,11 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <locale.h>
+#include <dbus/dbus-glib.h>
 
 #include "egg-debug.h"
 
 #include "gpk-common.h"
-#include "gpk-client.h"
 #include "gpk-error.h"
 
 /**
@@ -41,9 +41,10 @@
 	GOptionContext *context;
 	gboolean ret;
 	gboolean verbose = FALSE;
-	GError *error;
-	GpkClient *gclient;
+	GError *error = NULL;
 	gchar **packages = NULL;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
 
 	const GOptionEntry options[] = {
 		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
@@ -77,22 +78,52 @@
 	/* TRANSLATORS: application name to pass to to the user if there are not enough privs */
 	ret = gpk_check_privileged_user (_("Package Name Installer"), TRUE);
 	if (!ret)
-		return 1;
+		goto out;
 
 	if (packages == NULL) {
 		/* TRANSLATORS: failed */
 		gpk_error_dialog (_("Failed to install package from name"),
 				  /* TRANSLATORS: nothing was specified */
 				  _("You need to specify a package to install"), NULL);
-		return 1;
+		goto out;
 	}
 
-	error = NULL;
-	gclient = gpk_client_new ();
-	gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	ret = gpk_client_install_package_names (gclient, packages, NULL);
-	g_strfreev (packages);
-	g_object_unref (gclient);
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		egg_warning ("Cannot connect to session service");
+		goto out;
+	}
 
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallPackageNames", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, packages, /* data */
+				 G_TYPE_STRING, "", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (packages);
 	return !ret;
 }

Modified: trunk/src/gpk-install-provide-file.c
==============================================================================
--- trunk/src/gpk-install-provide-file.c	(original)
+++ trunk/src/gpk-install-provide-file.c	Tue Apr 14 16:28:59 2009
@@ -25,11 +25,11 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <locale.h>
+#include <dbus/dbus-glib.h>
 
 #include "egg-debug.h"
 
 #include "gpk-common.h"
-#include "gpk-client.h"
 #include "gpk-error.h"
 
 /**
@@ -41,12 +41,17 @@
 	GOptionContext *context;
 	gboolean ret;
 	gboolean verbose = FALSE;
-	GError *error;
-	GpkClient *gclient;
+	GError *error = NULL;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
+	gchar **files = NULL;
 
 	const GOptionEntry options[] = {
 		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
 		  _("Show extra debugging information"), NULL },
+		{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &files,
+		/* TRANSLATORS: command line option: a list of files to install */
+		  _("Local files to install"), NULL },
 		{ NULL}
 	};
 
@@ -74,28 +79,52 @@
 	/* TRANSLATORS: application name to pass to to the user if there are not enough privs */
 	ret = gpk_check_privileged_user (_("Single File Installer"), TRUE);
 	if (!ret)
-		return 1;
+		goto out;
 
-	if (argc < 2) {
+	if (files == NULL) {
 		/* TRANSLATORS: nothing done */
 		gpk_error_dialog (_("Failed to install a package to provide a file"),
 				  /* TRANSLATORS: nothig was specified */
 				  _("You need to specify a filename to install"), NULL);
-		return 1;
+		goto out;
 	}
-	if (argc > 2) {
-		/* TRANSLATORS: nothing done */
-		gpk_error_dialog (_("Failed to install packages to provide files"),
-				  /* TRANSLATORS: more than one thing was specified */
-				  _("You can only specify one filename to install"), NULL);
-		return 1;
+
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
 	}
 
-	error = NULL;
-	gclient = gpk_client_new ();
-	gpk_client_set_interaction (gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	ret = gpk_client_install_provide_file (gclient, argv[1], NULL);
-	g_object_unref (gclient);
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		egg_warning ("Cannot connect to session service");
+		goto out;
+	}
 
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallProvideFiles", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, files, /* data */
+				 G_TYPE_STRING, "", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		egg_warning ("%s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (files);
 	return !ret;
 }

Added: trunk/src/gpk-modal-dialog.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-modal-dialog.c	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,1022 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard 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 <errno.h>
+#include <signal.h>
+
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <glib/gi18n.h>
+#include <packagekit-glib/packagekit.h>
+
+#include "egg-debug.h"
+#include "egg-string.h"
+
+#include "gpk-animated-icon.h"
+#include "gpk-modal-dialog.h"
+#include "gpk-common.h"
+#include "gpk-gnome.h"
+#include "gpk-enum.h"
+#include "gpk-desktop.h"
+
+static void     gpk_modal_dialog_finalize	(GObject		*object);
+
+#define GPK_MODAL_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogPrivate))
+
+struct _GpkModalDialogPrivate
+{
+	GtkBuilder		*builder;
+	guint			 pulse_timer_id;
+	gboolean		 show_progress_files;
+	gboolean		 has_parent;
+	GMainLoop		*loop;
+	GtkResponseType		 response;
+	GtkListStore		*store;
+	gchar			*help_id;
+	gchar			*title;
+	gboolean		 set_image;
+	GpkModalDialogPage	 page;
+	PkBitfield		 options;
+	GtkWidget		*image_status;
+};
+
+enum {
+	GPK_MODAL_DIALOG_CLOSE,
+	GPK_MODAL_DIALOG_QUIT,
+	GPK_MODAL_DIALOG_ACTION,
+	GPK_MODAL_DIALOG_HELP,
+	GPK_MODAL_DIALOG_CANCEL,
+	LAST_SIGNAL
+};
+
+enum {
+	GPK_MODAL_DIALOG_STORE_IMAGE,
+	GPK_MODAL_DIALOG_STORE_ID,
+	GPK_MODAL_DIALOG_STORE_TEXT,
+	GPK_MODAL_DIALOG_STORE_LAST
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkModalDialog, gpk_modal_dialog, G_TYPE_OBJECT)
+
+/**
+ * gpk_modal_dialog_show_widget:
+ **/
+static void
+gpk_modal_dialog_show_widget (GpkModalDialog *dialog, const gchar *name, gboolean enabled)
+{
+	GtkWidget *widget;
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, name));
+	if (enabled)
+		gtk_widget_show (widget);
+	else
+		gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_modal_dialog_setup:
+ **/
+gboolean
+gpk_modal_dialog_setup (GpkModalDialog *dialog, GpkModalDialogPage page, PkBitfield options)
+{
+	GtkLabel *label;
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* reset state */
+	g_free (dialog->priv->help_id);
+	dialog->priv->help_id = NULL;
+	dialog->priv->set_image = FALSE;
+	dialog->priv->page = page;
+	dialog->priv->options = options;
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_label_set_label (label, "");
+	gpk_modal_dialog_set_action (dialog, NULL);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_present_with_time:
+ **/
+gboolean
+gpk_modal_dialog_present_with_time (GpkModalDialog *dialog, guint32 timestamp)
+{
+	GtkWidget *widget;
+	PkBitfield bitfield = 0;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_title"));
+	gtk_widget_show (widget);
+	gtk_widget_show (dialog->priv->image_status);
+	/* helper */
+	if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-question");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_HELP,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_FINISHED) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-information");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-question");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_HELP,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_WARNING) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-warning");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_PROGRESS) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-warning");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_HELP,
+						   GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR,
+						   -1);
+	}
+
+	/* we can specify extras */
+	bitfield += dialog->priv->options;
+
+	gpk_modal_dialog_show_widget (dialog, "button_help", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_HELP));
+	gpk_modal_dialog_show_widget (dialog, "button_cancel", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL));
+	gpk_modal_dialog_show_widget (dialog, "button_close", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE));
+	gpk_modal_dialog_show_widget (dialog, "button_action", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION));
+	gpk_modal_dialog_show_widget (dialog, "progressbar_percent", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR));
+	gpk_modal_dialog_show_widget (dialog, "label_message", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_MESSAGE));
+	gpk_modal_dialog_show_widget (dialog, "scrolledwindow_packages", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST));
+	gpk_modal_dialog_show_widget (dialog, "label_force_height", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PADDING));
+
+	/* always force width */
+	gpk_modal_dialog_show_widget (dialog, "label_force_width", TRUE);
+
+	/* show */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_realize (widget);
+	gtk_window_present_with_time (GTK_WINDOW (widget), timestamp);
+
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_present:
+ **/
+gboolean
+gpk_modal_dialog_present (GpkModalDialog *dialog)
+{
+	return gpk_modal_dialog_present_with_time (dialog, 0);
+}
+
+/**
+ * gpk_modal_dialog_set_parent:
+ **/
+gboolean
+gpk_modal_dialog_set_parent (GpkModalDialog *dialog, GdkWindow *window)
+{
+	GtkWidget *widget;
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* never set, and nothing now */
+	if (window == NULL && !dialog->priv->has_parent)
+		return TRUE;
+
+	/* not sure what to do here, should probably unparent somehow */
+	if (window == NULL) {
+		egg_warning ("parent set NULL when already modal with another window, setting non-modal");
+		widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+		gtk_window_set_modal (GTK_WINDOW (widget), FALSE);
+		dialog->priv->has_parent = FALSE;
+
+		/* use the saved title if it exists */
+		if (dialog->priv->title != NULL)
+			gpk_modal_dialog_set_title (dialog, dialog->priv->title);
+
+		return FALSE;
+	}
+
+	/* check we are a valid window */
+	if (!GDK_WINDOW (window)) {
+		egg_warning ("not a valid GdkWindow!");
+		return FALSE;
+	}
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_realize (widget);
+	gtk_window_set_modal (GTK_WINDOW (widget), TRUE);
+	gdk_window_set_transient_for (GTK_WIDGET (widget)->window, window);
+	dialog->priv->has_parent = TRUE;
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_window_title:
+ **/
+static gboolean
+gpk_modal_dialog_set_window_title (GpkModalDialog *dialog, const gchar *title)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (title != NULL, FALSE);
+
+	egg_debug ("setting window title: %s", title);
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_window_set_title (window, title);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_window_icon:
+ **/
+gboolean
+gpk_modal_dialog_set_window_icon (GpkModalDialog *dialog, const gchar *icon)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (icon != NULL, FALSE);
+
+	egg_debug ("setting window icon: %s", icon);
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_window_set_icon_name (window, icon);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_title:
+ **/
+gboolean
+gpk_modal_dialog_set_title (GpkModalDialog *dialog, const gchar *title)
+{
+	GtkLabel *label;
+	gchar *title_bold;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (title != NULL, FALSE);
+
+	/* only set the window title if we are non-modal */
+	if (!dialog->priv->has_parent)
+		gpk_modal_dialog_set_window_title (dialog, title);
+
+	/* we save this in case we are non-modal and have to use a title */
+	g_free (dialog->priv->title);
+	dialog->priv->title = g_strdup (title);
+
+	title_bold = g_strdup_printf ("<b><big>%s</big></b>", title);
+	egg_debug ("setting title: %s", title_bold);
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_title"));
+	gtk_label_set_markup (label, title_bold);
+	g_free (title_bold);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_message:
+ **/
+gboolean
+gpk_modal_dialog_set_message (GpkModalDialog *dialog, const gchar *message)
+{
+	GtkLabel *label;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (message != NULL, FALSE);
+
+	/* ignore this if it's uninteresting */
+	if (!dialog->priv->show_progress_files)
+		return FALSE;
+
+	egg_debug ("setting message: %s", message);
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_label_set_markup (label, message);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_action:
+ **/
+gboolean
+gpk_modal_dialog_set_action (GpkModalDialog *dialog, const gchar *action)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	egg_debug ("setting action: %s", action);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action"));
+	if (action != NULL)
+		gtk_button_set_label (GTK_BUTTON (widget), action);
+	else
+		gtk_widget_hide (widget);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_pulse_progress:
+ **/
+static gboolean
+gpk_modal_dialog_pulse_progress (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+	static guint rate_limit = 0;
+	
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* debug so we can catch polling */
+	if (rate_limit++ % 20 == 0)
+		egg_debug ("polling check");
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+	gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget));
+
+	/* if there's no slider, optimise out the polling */
+	if (!GTK_WIDGET_VISIBLE (widget)) {
+		dialog->priv->pulse_timer_id = 0;
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_make_progressbar_pulse:
+ **/
+static void
+gpk_modal_dialog_make_progressbar_pulse (GpkModalDialog *dialog)
+{
+	GtkProgressBar *progress_bar;
+	if (dialog->priv->pulse_timer_id == 0) {
+		progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+		gtk_progress_bar_set_pulse_step (progress_bar, 0.04);
+		dialog->priv->pulse_timer_id = g_timeout_add (75, (GSourceFunc) gpk_modal_dialog_pulse_progress, dialog);
+	}
+}
+
+/**
+ * gpk_modal_dialog_set_percentage:
+ **/
+gboolean
+gpk_modal_dialog_set_percentage (GpkModalDialog *dialog, guint percentage)
+{
+	GtkProgressBar *progress_bar;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	egg_debug ("setting percentage: %u", percentage);
+
+	progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	/* either pulse or set percentage */
+	if (percentage == PK_CLIENT_PERCENTAGE_INVALID)
+		gpk_modal_dialog_make_progressbar_pulse (dialog);
+	else
+		gtk_progress_bar_set_fraction (progress_bar, (gfloat) percentage / 100.0);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_remaining:
+ **/
+gboolean
+gpk_modal_dialog_set_remaining (GpkModalDialog *dialog, guint remaining)
+{
+	GtkProgressBar *progress_bar;
+	gchar *timestring = NULL;
+	gchar *text = NULL;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	egg_debug ("setting remaining: %u", remaining);
+	progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+
+	/* unknown */
+	if (remaining == 0) {
+		gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress_bar), "");
+		goto out;
+	}
+
+	/* get time text */
+	timestring = gpk_time_to_imprecise_string (remaining);
+	text = g_strdup_printf (_("Remaining time : %s"), timestring);
+	gtk_progress_bar_set_text (progress_bar, text);
+out:
+	g_free (timestring);
+	g_free (text);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_image:
+ **/
+gboolean
+gpk_modal_dialog_set_image (GpkModalDialog *dialog, const gchar *image)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (image != NULL, FALSE);
+
+	/* set state */
+	dialog->priv->set_image = TRUE;
+
+	egg_debug ("setting image: %s", image);
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	gtk_image_set_from_icon_name (GTK_IMAGE (dialog->priv->image_status), image, GTK_ICON_SIZE_DIALOG);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_image_status:
+ **/
+gboolean
+gpk_modal_dialog_set_image_status (GpkModalDialog *dialog, PkStatusEnum status)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* set state */
+	dialog->priv->set_image = TRUE;
+	gpk_set_animated_icon_from_status (GPK_ANIMATED_ICON (dialog->priv->image_status), status, GTK_ICON_SIZE_DIALOG);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_get_window:
+ **/
+GtkWindow *
+gpk_modal_dialog_get_window (GpkModalDialog *dialog)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), NULL);
+
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	return window;
+}
+
+/**
+ * gpk_modal_dialog_set_allow_cancel:
+ **/
+gboolean
+gpk_modal_dialog_set_allow_cancel (GpkModalDialog *dialog, gboolean can_cancel)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel"));
+	gtk_widget_set_sensitive (widget, can_cancel);
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_run:
+ **/
+GtkResponseType
+gpk_modal_dialog_run (GpkModalDialog *dialog)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	dialog->priv->response = GTK_RESPONSE_NONE;
+	g_main_loop_run (dialog->priv->loop);
+
+	return dialog->priv->response;
+}
+
+/**
+ * gpk_modal_dialog_close:
+ **/
+gboolean
+gpk_modal_dialog_close (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_hide (widget);
+
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_window_delete_cb:
+ **/
+static gboolean
+gpk_modal_dialog_window_delete_cb (GtkWidget *widget, GdkEvent *event, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_DELETE_EVENT;
+	gpk_modal_dialog_close (dialog);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	/* do not destroy the window */
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_button_close_cb:
+ **/
+static void
+gpk_modal_dialog_button_close_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_CLOSE;
+	g_main_loop_quit (dialog->priv->loop);
+
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CLOSE], 0);
+}
+
+/**
+ * gpk_modal_dialog_set_help_id:
+ **/
+gboolean
+gpk_modal_dialog_set_help_id (GpkModalDialog *dialog, const gchar *help_id)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (dialog->priv->help_id == NULL, FALSE);
+	dialog->priv->help_id = g_strdup (help_id);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_button_help_cb:
+ **/
+static void
+gpk_modal_dialog_button_help_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	gpk_gnome_help (dialog->priv->help_id);
+	g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_HELP], 0);
+}
+
+/**
+ * gpk_modal_dialog_button_action_cb:
+ **/
+static void
+gpk_modal_dialog_button_action_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_OK;
+	g_main_loop_quit (dialog->priv->loop);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_ACTION], 0);
+}
+
+/**
+ * gpk_modal_dialog_button_cancel_cb:
+ **/
+static void
+gpk_modal_dialog_button_cancel_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_CANCEL;
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CANCEL], 0);
+}
+
+/**
+ * gpk_modal_dialog_set_package_list:
+ **/
+gboolean
+gpk_modal_dialog_set_package_list (GpkModalDialog *dialog, const PkPackageList *list)
+{
+	GtkTreeIter iter;
+	const PkPackageObj *obj;
+	PkDesktop *desktop;
+	gchar *icon;
+	gchar *package_id;
+	gchar *text;
+	guint length;
+	guint i;
+	GtkWidget *widget;
+
+	gtk_list_store_clear (dialog->priv->store);
+
+	length = pk_package_list_get_size (list);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "scrolledwindow_packages"));
+	if (length > 5)
+		gtk_widget_set_size_request (widget, -1, 300);
+	else if (length > 1)
+		gtk_widget_set_size_request (widget, -1, 150);
+
+	desktop = pk_desktop_new ();
+	length = pk_package_list_get_size (list);
+
+	/* add each well */
+	for (i=0; i<length; i++) {
+		obj = pk_package_list_get_obj (list, i);
+
+		/* not installed, so ignore icon */
+		if (obj->info == PK_INFO_ENUM_DOWNLOADING ||
+		    obj->info == PK_INFO_ENUM_CLEANUP)
+			continue;
+
+		text = gpk_package_id_format_twoline (obj->id, obj->summary);
+		package_id = pk_package_id_to_string (obj->id);
+
+		/* get the icon */
+		icon = gpk_desktop_guess_icon_name (desktop, obj->id->name);
+		if (icon == NULL)
+			icon = g_strdup (gpk_info_enum_to_icon_name (PK_INFO_ENUM_INSTALLED));
+
+		gtk_list_store_append (dialog->priv->store, &iter);
+		gtk_list_store_set (dialog->priv->store, &iter,
+				    GPK_MODAL_DIALOG_STORE_IMAGE, icon,
+				    GPK_MODAL_DIALOG_STORE_ID, package_id,
+				    GPK_MODAL_DIALOG_STORE_TEXT, text,
+				    -1);
+		g_free (icon);
+		g_free (text);
+		g_free (package_id);
+	}
+
+	g_object_unref (desktop);
+
+	return TRUE;
+}
+
+
+/**
+ * gpk_dialog_treeview_for_package_list:
+ **/
+static gboolean
+gpk_dialog_treeview_for_package_list (GpkModalDialog *dialog)
+{
+	GtkTreeView *treeview;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+
+	treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages"));
+
+	/* column for images */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DND, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer, "icon-name", GPK_MODAL_DIALOG_STORE_IMAGE);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for name */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the package name */
+	column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer,
+							   "markup", GPK_MODAL_DIALOG_STORE_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_MODAL_DIALOG_STORE_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* set some common options */
+	gtk_tree_view_set_headers_visible (treeview, FALSE);
+	selection = gtk_tree_view_get_selection (treeview);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+	gtk_tree_selection_unselect_all (selection);
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_class_init:
+ * @klass: The GpkModalDialogClass
+ **/
+static void
+gpk_modal_dialog_class_init (GpkModalDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_modal_dialog_finalize;
+	g_type_class_add_private (klass, sizeof (GpkModalDialogPrivate));
+	signals [GPK_MODAL_DIALOG_QUIT] =
+		g_signal_new ("quit",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_CLOSE] =
+		g_signal_new ("close",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_ACTION] =
+		g_signal_new ("action",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_CANCEL] =
+		g_signal_new ("cancel",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_HELP] =
+		g_signal_new ("help",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
+
+/**
+ * gpk_modal_dialog_init:
+ * @dialog: This class instance
+ **/
+static void
+gpk_modal_dialog_init (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+	GtkTreeView *treeview;
+	guint retval;
+	GError *error = NULL;
+	GtkBox *box;
+
+	dialog->priv = GPK_MODAL_DIALOG_GET_PRIVATE (dialog);
+
+	dialog->priv->loop = g_main_loop_new (NULL, FALSE);
+	dialog->priv->response = GTK_RESPONSE_NONE;
+	dialog->priv->pulse_timer_id = 0;
+	dialog->priv->show_progress_files = TRUE;
+	dialog->priv->has_parent = FALSE;
+	dialog->priv->set_image = FALSE;
+	dialog->priv->page = GPK_MODAL_DIALOG_PAGE_UNKNOWN;
+	dialog->priv->options = 0;
+	dialog->priv->help_id = NULL;
+	dialog->priv->title = NULL;
+
+	dialog->priv->store = gtk_list_store_new (GPK_MODAL_DIALOG_STORE_LAST,
+						  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* get UI */
+	dialog->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (dialog->priv->builder, GPK_DATA "/gpk-client.ui", &error);
+	if (error != NULL) {
+		egg_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+		goto out_build;
+	}
+
+	/* add animated widget */
+	dialog->priv->image_status = gpk_animated_icon_new ();
+	box = GTK_BOX (gtk_builder_get_object (dialog->priv->builder, "hbox_status"));
+	gtk_box_pack_start (box, dialog->priv->image_status, FALSE, FALSE, 0);
+	gtk_widget_show (dialog->priv->image_status);
+
+	gpk_dialog_treeview_for_package_list (dialog);
+
+	treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages"));
+	gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (dialog->priv->store));
+
+	/* common stuff */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_modal_dialog_window_delete_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_close_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_help"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_help_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_action_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_cancel_cb), dialog);
+
+	/* set the message text an absolute width so it's forced to wrap */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "hbox_message"));
+	gtk_widget_set_size_request (widget, 400, -1);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_widget_set_size_request (widget, 400, -1);
+
+out_build:
+	/* clear status and progress text */
+	gpk_modal_dialog_set_window_title (dialog, "");
+	gpk_modal_dialog_set_title (dialog, "");
+	gpk_modal_dialog_set_message (dialog, "");
+}
+
+/**
+ * gpk_modal_dialog_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_modal_dialog_finalize (GObject *object)
+{
+	GpkModalDialog *dialog;
+	g_return_if_fail (GPK_IS_CLIENT_DIALOG (object));
+
+	dialog = GPK_MODAL_DIALOG (object);
+	g_return_if_fail (dialog->priv != NULL);
+
+	/* no updates, we're about to rip the builder up  */
+	if (dialog->priv->pulse_timer_id != 0)
+		g_source_remove (dialog->priv->pulse_timer_id);
+
+	/* if it's closed, then hide */
+	gpk_modal_dialog_close (dialog);
+
+	/* shouldn't be, but just in case */
+	if (g_main_loop_is_running (dialog->priv->loop)) {
+		egg_warning ("mainloop running on exit");
+		g_main_loop_quit (dialog->priv->loop);
+	}
+
+	g_object_unref (dialog->priv->store);
+	g_object_unref (dialog->priv->builder);
+	g_main_loop_unref (dialog->priv->loop);
+	g_free (dialog->priv->help_id);
+	g_free (dialog->priv->title);
+
+	G_OBJECT_CLASS (gpk_modal_dialog_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_modal_dialog_new:
+ *
+ * Return value: a new GpkModalDialog object.
+ **/
+GpkModalDialog *
+gpk_modal_dialog_new (void)
+{
+	GpkModalDialog *dialog;
+	dialog = g_object_new (GPK_TYPE_CLIENT_DIALOG, NULL);
+	return GPK_MODAL_DIALOG (dialog);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+gpk_modal_dialog_test (EggTest *test)
+{
+	GtkResponseType button;
+	GpkModalDialog *dialog = NULL;
+	PkPackageList *list;
+	PkPackageId *id;
+
+	if (!egg_test_start (test, "GpkModalDialog"))
+		return;
+
+	/************************************************************/
+	egg_test_title (test, "get GpkModalDialog object");
+	dialog = gpk_modal_dialog_new ();
+	if (dialog != NULL)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, NULL);
+
+	/* set some packages */
+	list = pk_package_list_new ();
+	id = pk_package_id_new_from_list ("totem", "0.0.1", "i386", "fedora-newkey");
+	pk_package_list_add (list, PK_INFO_ENUM_INSTALLED, id, "Totem is a music player for GNOME");
+	pk_package_list_add (list, PK_INFO_ENUM_AVAILABLE, id, "Amarok is a music player for KDE");
+	gpk_modal_dialog_set_package_list (dialog, list);
+	pk_package_id_free (id);
+	g_object_unref (list);
+
+	/************************************************************/
+	egg_test_title (test, "help button");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+	gpk_modal_dialog_set_window_title (dialog, "PackageKit self test");
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press close");
+	gpk_modal_dialog_set_image (dialog, "dialog-warning");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	if (button == GTK_RESPONSE_CLOSE)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "got id %i", button);
+
+	/************************************************************/
+	egg_test_title (test, "confirm button");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_title (dialog, "Button press test with a really really long title");
+	gpk_modal_dialog_set_message (dialog, "Please press Uninstall\n\nThis is a really really, really,\nreally long title <i>with formatting</i>");
+	gpk_modal_dialog_set_image (dialog, "dialog-information");
+	gpk_modal_dialog_set_action (dialog, "Uninstall");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	if (button == GTK_RESPONSE_OK)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "got id %i", button);
+
+	/************************************************************/
+	egg_test_title (test, "no message");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	gpk_modal_dialog_set_title (dialog, "Refresh cache");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_REFRESH_CACHE);
+	gpk_modal_dialog_set_percentage (dialog, 101);
+	gpk_modal_dialog_present (dialog);
+	gpk_modal_dialog_run (dialog);
+	egg_test_success (test, NULL);
+
+	/************************************************************/
+	egg_test_title (test, "progress");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press cancel");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_RUNNING);
+	gpk_modal_dialog_set_percentage (dialog, 50);
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	if (button == GTK_RESPONSE_CANCEL)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "got id %i", button);
+
+	/************************************************************/
+	egg_test_title (test, "progress");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1));
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press close");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_INSTALL);
+	gpk_modal_dialog_set_percentage (dialog, 101);
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	if (button == GTK_RESPONSE_CLOSE)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "got id %i", button);
+
+	/************************************************************/
+	egg_test_title (test, "confirm install button");
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press Install if you can see the package list");
+	gpk_modal_dialog_set_image (dialog, "dialog-information");
+	gpk_modal_dialog_set_action (dialog, "Install");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	if (button == GTK_RESPONSE_OK)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "got id %i", button);
+
+	gpk_modal_dialog_close (dialog);
+
+	g_object_unref (dialog);
+
+	egg_test_end (test);
+}
+#endif
+

Added: trunk/src/gpk-modal-dialog.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-modal-dialog.h	Tue Apr 14 16:28:59 2009
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard 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 __GPK_MODAL_DIALOG_H
+#define __GPK_MODAL_DIALOG_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_CLIENT_DIALOG		(gpk_modal_dialog_get_type ())
+#define GPK_MODAL_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialog))
+#define GPK_MODAL_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass))
+#define GPK_IS_CLIENT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_CLIENT_DIALOG))
+#define GPK_IS_CLIENT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_CLIENT_DIALOG))
+#define GPK_MODAL_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass))
+#define GPK_MODAL_DIALOG_ERROR		(gpk_modal_dialog_error_quark ())
+#define GPK_MODAL_DIALOG_TYPE_ERROR	(gpk_modal_dialog_error_get_type ())
+
+/**
+ * GpkModalDialogPage:
+ */
+typedef enum
+{
+	GPK_MODAL_DIALOG_PAGE_CONFIRM,
+	GPK_MODAL_DIALOG_PAGE_PROGRESS,
+	GPK_MODAL_DIALOG_PAGE_FINISHED,
+	GPK_MODAL_DIALOG_PAGE_WARNING,
+	GPK_MODAL_DIALOG_PAGE_CUSTOM,
+	GPK_MODAL_DIALOG_PAGE_UNKNOWN
+} GpkModalDialogPage;
+
+/**
+ * GpkModalDialogWidgets:
+ */
+typedef enum
+{
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_HELP,
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL,
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+	GPK_MODAL_DIALOG_WIDGET_PADDING,
+	GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST,
+	GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR,
+	GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+	GPK_MODAL_DIALOG_WIDGET_UNKNOWN
+} GpkModalDialogWidgets;
+
+/* helpers */
+#define GPK_MODAL_DIALOG_PACKAGE_PADDING	pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_PADDING, GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1)
+#define GPK_MODAL_DIALOG_PACKAGE_LIST		pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST)
+#define GPK_MODAL_DIALOG_BUTTON_ACTION		pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION)
+
+typedef struct _GpkModalDialogPrivate	 GpkModalDialogPrivate;
+typedef struct _GpkModalDialog		 GpkModalDialog;
+typedef struct _GpkModalDialogClass	 GpkModalDialogClass;
+
+struct _GpkModalDialog
+{
+	GObject				 parent;
+	GpkModalDialogPrivate		*priv;
+};
+
+struct _GpkModalDialogClass
+{
+	GObjectClass	parent_class;
+};
+
+GQuark		 gpk_modal_dialog_error_quark		(void);
+GType		 gpk_modal_dialog_get_type		(void);
+GpkModalDialog	*gpk_modal_dialog_new			(void);
+
+gboolean	 gpk_modal_dialog_present		(GpkModalDialog	*dialog);
+gboolean	 gpk_modal_dialog_present_with_time	(GpkModalDialog	*dialog,
+							 guint32		 timestamp);
+gboolean	 gpk_modal_dialog_set_package_list	(GpkModalDialog	*dialog,
+							 const PkPackageList	*list);
+gboolean	 gpk_modal_dialog_set_parent		(GpkModalDialog	*dialog,
+							 GdkWindow		*window);
+gboolean	 gpk_modal_dialog_set_window_icon	(GpkModalDialog	*dialog,
+							 const gchar		*icon);
+gboolean	 gpk_modal_dialog_set_title		(GpkModalDialog	*dialog,
+							 const gchar		*title);
+gboolean	 gpk_modal_dialog_set_message		(GpkModalDialog	*dialog,
+							 const gchar		*message);
+gboolean	 gpk_modal_dialog_set_action		(GpkModalDialog	*dialog,
+							 const gchar		*action);
+gboolean	 gpk_modal_dialog_set_percentage	(GpkModalDialog	*dialog,
+							 guint			 percentage);
+gboolean	 gpk_modal_dialog_set_remaining	(GpkModalDialog	*dialog,
+							 guint			 remaining);
+gboolean	 gpk_modal_dialog_set_image		(GpkModalDialog	*dialog,
+							 const gchar		*image);
+gboolean	 gpk_modal_dialog_set_image_status	(GpkModalDialog	*dialog,
+							 PkStatusEnum		 status);
+gboolean	 gpk_modal_dialog_set_allow_cancel	(GpkModalDialog	*dialog,
+							 gboolean		 can_cancel);
+gboolean	 gpk_modal_dialog_set_help_id		(GpkModalDialog	*dialog,
+							 const gchar		*help_id);
+GtkWindow	*gpk_modal_dialog_get_window		(GpkModalDialog	*dialog);
+GtkResponseType	 gpk_modal_dialog_run			(GpkModalDialog	*dialog);
+gboolean	 gpk_modal_dialog_close		(GpkModalDialog	*dialog);
+gboolean	 gpk_modal_dialog_setup		(GpkModalDialog	*dialog,
+							 GpkModalDialogPage	 page,
+							 PkBitfield		 options);
+
+G_END_DECLS
+
+#endif /* __GPK_MODAL_DIALOG_H */
+

Modified: trunk/src/gpk-self-test.c
==============================================================================
--- trunk/src/gpk-self-test.c	(original)
+++ trunk/src/gpk-self-test.c	Tue Apr 14 16:28:59 2009
@@ -30,7 +30,7 @@
 void egg_string_test (EggTest *test);
 void gpk_dbus_test (EggTest *test);
 void gpk_language_test (EggTest *test);
-void gpk_client_dialog_test (EggTest *test);
+void gpk_modal_dialog_test (EggTest *test);
 void gpk_client_test (EggTest *test);
 void gpk_error_test (EggTest *test);
 
@@ -54,8 +54,8 @@
 //	gpk_dbus_test (test);
 	gpk_language_test (test);
 	gpk_error_test (test);
-	gpk_client_test (test);
-	gpk_client_dialog_test (test);
+//	gpk_client_test (test);
+	gpk_modal_dialog_test (test);
 
 	return egg_test_finish (test);
 }

Modified: trunk/src/gpk-update-viewer.c
==============================================================================
--- trunk/src/gpk-update-viewer.c	(original)
+++ trunk/src/gpk-update-viewer.c	Tue Apr 14 16:28:59 2009
@@ -46,12 +46,11 @@
 #include "gpk-cell-renderer-info.h"
 #include "gpk-cell-renderer-restart.h"
 #include "gpk-cell-renderer-percentage.h"
-#include "gpk-client.h"
 #include "gpk-enum.h"
 #include "gpk-helper-repo-signature.h"
 #include "gpk-helper-eula.h"
 
-#define GPK_UPDATE_VIEWER_AUTO_CLOSE_TIMEOUT	10 /* seconds */
+#define GPK_UPDATE_VIEWER_AUTO_QUIT_TIMEOUT	10 /* seconds */
 #define GPK_UPDATE_VIEWER_AUTO_RESTART_TIMEOUT	60 /* seconds */
 #define GPK_UPDATE_VIEWER_MOBILE_SMALL_SIZE	512*1024 /* bytes */
 #define GNOME_SESSION_MANAGER_SERVICE		"org.gnome.SessionManager"
@@ -72,8 +71,8 @@
 static EggMarkdown *markdown = NULL;
 static PkPackageId *package_id_last = NULL;
 static PkRestartEnum restart_update = PK_RESTART_ENUM_NONE;
-static gboolean running_hidden = FALSE;
 static guint size_total = 0;
+static GConfClient *gconf_client = NULL;
 
 enum {
 	GPK_UPDATES_COLUMN_TEXT,
@@ -157,15 +156,94 @@
 }
 
 /**
- * gpk_update_viewer_button_close_cb:
+ * gpk_update_viewer_quit:
  **/
 static void
-gpk_update_viewer_button_close_cb (GtkWidget *widget, gpointer data)
+gpk_update_viewer_quit (void)
 {
+	gboolean ret;
+	gboolean allow_cancel = FALSE;
+	GError *error = NULL;
+	PkRoleEnum role;
+	PkStatusEnum status;
+	GtkWindow *window;
+	GtkWidget *dialog;
+	GtkResponseType response;
+
+	/* are we in a transaction */
+	ret = pk_client_get_role (client_primary, &role, NULL, &error);
+	if (!ret) {
+		egg_warning ("failed to get role: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	if (role == PK_ROLE_ENUM_UNKNOWN) {
+		egg_debug ("no role, so quitting");
+		goto out;
+	}
+	ret = pk_client_get_status (client_primary, &status, &error);
+	if (!ret) {
+		egg_warning ("failed to get status: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	if (status == PK_STATUS_ENUM_FINISHED) {
+		egg_debug ("status is finished, so quitting");
+		goto out;
+	}
+
+	/* can we easily cancel */
+	ret = pk_client_get_allow_cancel (client_primary, &allow_cancel, &error);
+	if (!ret) {
+		egg_warning ("failed to get allow cancel state: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* cancel the transaction */
+	if (allow_cancel) {
+		ret = pk_client_cancel (client_primary, &error);
+		if (!ret) {
+			egg_warning ("failed to cancel client: %s", error->message);
+			g_error_free (error);
+		}
+		goto out;
+	}
+
+	/* show modal dialog asking for confirmation */
+	window = GTK_WINDOW (gtk_builder_get_object (builder, "dialog_updates"));
+	dialog = gtk_message_dialog_new (window, GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL,
+					 "%s", _("Cannot cancel running task"));
+
+	/* TRANSLATORS: this is the button text when we check if it's okay to download */
+	gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-quit", GTK_RESPONSE_OK);
+
+	/* TRANSLATORS, user clicked the [x] when we cannot cancel what we are doing */
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
+						  "%s", _("There are tasks that cannot be cancelled."));
+
+	gtk_window_set_icon_name (GTK_WINDOW(dialog), GPK_ICON_SOFTWARE_INSTALLER);
+	response = gtk_dialog_run (GTK_DIALOG(dialog));
+	gtk_widget_destroy (dialog);
+
+	/* pressed cancel or [x] */
+	if (response != GTK_RESPONSE_OK)
+		return;
+out:
 	g_main_loop_quit (loop);
 }
 
 /**
+ * gpk_update_viewer_button_quit_cb:
+ **/
+static void
+gpk_update_viewer_button_quit_cb (GtkWidget *widget, gpointer data)
+{
+	gpk_update_viewer_quit ();
+}
+
+/**
  * gpk_update_viewer_undisable_packages:
  **/
 static void
@@ -221,6 +299,11 @@
 	if (size < GPK_UPDATE_VIEWER_MOBILE_SMALL_SIZE)
 		goto out;
 
+	/* not when ignored */
+	ret = gconf_client_get_bool (gconf_client, GPK_CONF_UPDATE_VIEWER_MOBILE_BBAND, NULL);
+	if (!ret)
+		goto out;
+
 	/* show modal dialog */
 	window = GTK_WINDOW (gtk_builder_get_object (builder, "dialog_updates"));
 	dialog = gtk_message_dialog_new (window, GTK_DIALOG_MODAL,
@@ -354,23 +437,6 @@
 }
 
 /**
- * gpk_update_viewer_button_cancel_cb:
- **/
-static void
-gpk_update_viewer_button_cancel_cb (GtkWidget *widget, gpointer data)
-{
-	gboolean ret;
-	GError *error = NULL;
-
-	/* cancel the transaction */
-	ret = pk_client_cancel (client_primary, &error);
-	if (!ret) {
-		egg_warning ("failed to cancel client: %s", error->message);
-		g_error_free (error);
-	}
-}
-
-/**
  * gpk_update_viewer_button_upgrade_cb:
  **/
 static void
@@ -392,43 +458,8 @@
 static gboolean
 gpk_update_viewer_button_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-	gboolean ret;
-	GError *error = NULL;
-	PkRoleEnum role;
-	PkStatusEnum status;
-
-	/* if we are in a transaction, don't quit, just hide, as we want to return
-	 * to this state if the dialog is run again */
-	ret = pk_client_get_role (client_primary, &role, NULL, &error);
-	if (!ret) {
-		egg_warning ("failed to get role: %s", error->message);
-		g_error_free (error);
-		goto out;
-	}
-	if (role == PK_ROLE_ENUM_UNKNOWN) {
-		egg_debug ("no role, so quitting");
-		goto out;
-	}
-	ret = pk_client_get_status (client_primary, &status, &error);
-	if (!ret) {
-		egg_warning ("failed to get status: %s", error->message);
-		g_error_free (error);
-		goto out;
-	}
-	if (status == PK_STATUS_ENUM_FINISHED) {
-		egg_debug ("status is finished, so quitting");
-		goto out;
-	}
-
-	/* hide window */
-	egg_debug ("hiding to preserve state");
-	running_hidden = TRUE;
-	widget = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_updates"));
-	gtk_widget_hide (widget);
+	gpk_update_viewer_quit ();
 	return TRUE;
-out:
-	g_main_loop_quit (loop);
-	return FALSE;
 }
 
 /**
@@ -632,31 +663,6 @@
 }
 
 /**
- * gpk_update_viewer_reconsider_buttons:
- **/
-static void
-gpk_update_viewer_reconsider_buttons (gpointer data)
-{
-	GtkWidget *widget;
-	PkStatusEnum status;
-
-	/* cancel buttons? */
-	pk_client_get_status (client_primary, &status, NULL);
-	egg_debug ("status is %s", pk_status_enum_to_text (status));
-	if (status == PK_STATUS_ENUM_FINISHED) {
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_install"));
-		gtk_widget_show (widget);
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_cancel"));
-		gtk_widget_hide (widget);
-	} else {
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_install"));
-		gtk_widget_hide (widget);
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_cancel"));
-		gtk_widget_show (widget);
-	}
-}
-
-/**
  * gpk_update_viewer_auto_shutdown:
  **/
 static gboolean
@@ -726,7 +732,7 @@
 	len = PK_OBJ_LIST(update_list)->len;
 	if (len == 0) {
 		/* hide close button */
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_close"));
+		widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_quit"));
 		gtk_widget_hide (widget);
 
 		/* show a new title */
@@ -739,13 +745,13 @@
 		/* show modal dialog */
 		widget = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_updates"));
 		dialog = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_MODAL,
-						 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
+						 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
 						 /* TRANSLATORS: title: warn the user they are quitting with unapplied changes */
-						 "%s", _("No updates available"));
+						 "%s", _("All software is up to date"));
 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
 							  "%s",
 							  /* TRANSLATORS: tell the user the problem */
-							  _("There are no updates available for your computer at this time."));
+							  _("There are no software updates available for your computer at this time."));
 		gtk_window_set_icon_name (GTK_WINDOW(dialog), GPK_ICON_SOFTWARE_INSTALLER);
 
 		/* setup a callback so we autoclose */
@@ -819,6 +825,8 @@
 {
 	GtkWidget *widget;
 	const gchar *text;
+	GdkDisplay *display;
+	GdkCursor *cursor;
 
 	egg_debug ("status %s", pk_status_enum_to_text (status));
 
@@ -831,6 +839,11 @@
 	/* set cursor back to normal */
 	if (status == PK_STATUS_ENUM_FINISHED) {
 		gdk_window_set_cursor (widget->window, NULL);
+	} else {
+		display = gdk_display_get_default ();
+		cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+		gdk_window_set_cursor (widget->window, cursor);
+		gdk_cursor_unref (cursor);
 	}
 
 	/* clear package */
@@ -862,8 +875,7 @@
 	gtk_image_set_from_icon_name (GTK_IMAGE (widget), gpk_status_enum_to_icon_name (status), GTK_ICON_SIZE_BUTTON);
 	gtk_widget_show (widget);
 out:
-	/* set state */
-	gpk_update_viewer_reconsider_buttons (NULL);
+	return;
 }
 
 /**
@@ -1017,7 +1029,9 @@
 
 	/* info */
 	renderer = gpk_cell_renderer_info_new ();
-	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	g_object_set (renderer,
+		      "stock-size", GTK_ICON_SIZE_BUTTON,
+		      "ignore-values", "unknown,normal", NULL);
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute (column, renderer, "value", GPK_UPDATES_COLUMN_INFO);
 
@@ -1069,7 +1083,9 @@
 
 	/* status */
 	renderer = gpk_cell_renderer_info_new ();
-	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	g_object_set (renderer,
+		      "stock-size", GTK_ICON_SIZE_BUTTON,
+		      "ignore-values", "unknown", NULL);
 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
 	gtk_tree_view_column_add_attribute (column, renderer, "value", GPK_UPDATES_COLUMN_STATUS);
 
@@ -1297,16 +1313,19 @@
 }
 
 /**
- * pk_packages_treeview_clicked_cb:
+ * gpk_packages_treeview_clicked_cb:
  **/
 static void
-pk_packages_treeview_clicked_cb (GtkTreeSelection *selection, gpointer data)
+gpk_packages_treeview_clicked_cb (GtkTreeSelection *selection, gpointer data)
 {
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	gchar *package_id;
 	PkUpdateDetailObj *obj = NULL;
 
+	/* set loading text */
+	gtk_text_buffer_set_text (text_buffer, _("Loading..."), -1);
+
 	/* This will only work in single or browse selection mode! */
 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
 		gtk_tree_model_get (model, &iter,
@@ -1455,10 +1474,10 @@
 }
 
 /**
- * gpk_update_viewer_requeue:
+ * gpk_update_viewer_primary_requeue:
  **/
 static gboolean
-gpk_update_viewer_requeue (gpointer data)
+gpk_update_viewer_primary_requeue (gpointer data)
 {
 	gboolean ret;
 	GError *error = NULL;
@@ -1561,11 +1580,8 @@
 	widget = GTK_WIDGET (gtk_builder_get_object (builder, "progressbar_progress"));
 	gtk_widget_hide (widget);
 
-	/* hidden window, so quit at this point */
-	if (running_hidden) {
-		egg_debug ("transaction finished whilst hidden, so exit");
-		g_main_loop_quit (loop);
-	}
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_quit"));
+	gtk_widget_set_sensitive (widget, TRUE);
 
 	/* if secondary, ignore */
 	if (client == client_primary &&
@@ -1640,7 +1656,7 @@
 	if (role == PK_ROLE_ENUM_INSTALL_SIGNATURE ||
 	    role == PK_ROLE_ENUM_ACCEPT_EULA) {
 		if (exit == PK_EXIT_ENUM_SUCCESS)
-			gpk_update_viewer_requeue (NULL);
+			gpk_update_viewer_primary_requeue (NULL);
 		else
 			gpk_update_viewer_undisable_packages ();
 	}
@@ -1977,8 +1993,6 @@
 	if (command == UNIQUE_ACTIVATE) {
 		window = GTK_WINDOW (gtk_builder_get_object (builder, "dialog_updates"));
 		gtk_window_present (window);
-		/* not hidden anymore */
-		running_hidden = FALSE;
 	}
 }
 
@@ -2027,21 +2041,9 @@
 static void
 gpk_update_viewer_allow_cancel_cb (PkClient *client, gboolean allow_cancel, gpointer data)
 {
-	GdkDisplay *display;
-	GdkCursor *cursor;
 	GtkWidget *widget;
-	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_cancel"));
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_quit"));
 	gtk_widget_set_sensitive (widget, allow_cancel);
-
-	/* set cursor */
-	if (allow_cancel) {
-		gdk_window_set_cursor (widget->window, NULL);
-	} else {
-		display = gdk_display_get_default ();
-		cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
-		gdk_window_set_cursor (widget->window, cursor);
-		gdk_cursor_unref (cursor);
-	}
 }
 
 /**
@@ -2069,7 +2071,6 @@
 	if (type != GTK_RESPONSE_YES) {
 		/* we've ruined the old one by making the checkboxes insensitive */
 		gpk_update_viewer_get_new_update_list ();
-		gpk_update_viewer_reconsider_buttons (NULL);
 		goto out;
 	}
 
@@ -2111,7 +2112,6 @@
 	if (type != GTK_RESPONSE_YES) {
 		/* we've ruined the old one by making the checkboxes insensitive */
 		gpk_update_viewer_get_new_update_list ();
-		gpk_update_viewer_reconsider_buttons (NULL);
 		goto out;
 	}
 
@@ -2431,6 +2431,9 @@
 		goto unique_out;
 	}
 
+	/* get GConf instance */
+	gconf_client = gconf_client_get_default ();
+
 	g_signal_connect (unique_app, "message-received", G_CALLBACK (gpk_update_viewer_message_received_cb), NULL);
 
 	markdown = egg_markdown_new ();
@@ -2491,6 +2494,7 @@
 
 	main_window = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_updates"));
 	g_signal_connect (main_window, "delete_event", G_CALLBACK (gpk_update_viewer_button_delete_event_cb), NULL);
+	gtk_window_set_icon_name (GTK_WINDOW (main_window), GPK_ICON_SOFTWARE_INSTALLER);
 
 	/* helpers */
 	helper_repo_signature = gpk_helper_repo_signature_new ();
@@ -2543,7 +2547,7 @@
 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
 	g_signal_connect (selection, "changed",
-			  G_CALLBACK (pk_packages_treeview_clicked_cb), NULL);
+			  G_CALLBACK (gpk_packages_treeview_clicked_cb), NULL);
 
 	/* bottom UI */
 	widget = GTK_WIDGET (gtk_builder_get_object (builder, "progressbar_progress"));
@@ -2569,17 +2573,11 @@
 	gtk_widget_set_sensitive (widget, FALSE);
 
 	/* close button */
-	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_close"));
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_quit"));
 	g_signal_connect (widget, "clicked",
-			  G_CALLBACK (gpk_update_viewer_button_close_cb), NULL);
+			  G_CALLBACK (gpk_update_viewer_button_quit_cb), NULL);
 	gtk_window_set_focus (GTK_WINDOW(main_window), widget);
 
-	/* hide cancel button */
-	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_cancel"));
-	gtk_widget_hide (widget);
-	g_signal_connect (widget, "clicked",
-			  G_CALLBACK (gpk_update_viewer_button_cancel_cb), NULL);
-
 	/* upgrade button */
 	widget = GTK_WIDGET (gtk_builder_get_object (builder, "button_upgrade"));
 	g_signal_connect (widget, "clicked",
@@ -2636,11 +2634,11 @@
 
 	g_object_unref (helper_eula);
 	g_object_unref (helper_repo_signature);
-	g_object_unref (builder);
 	g_object_unref (list_store_updates);
 	g_object_unref (text_buffer);
 	pk_package_id_free (package_id_last);
 out_build:
+	g_object_unref (gconf_client);
 	g_object_unref (control);
 	g_object_unref (markdown);
 	g_object_unref (client_primary);

Modified: trunk/src/gpk-vendor.h
==============================================================================
--- trunk/src/gpk-vendor.h	(original)
+++ trunk/src/gpk-vendor.h	Tue Apr 14 16:28:59 2009
@@ -49,7 +49,7 @@
 } GpkVendorClass;
 
 /**
- * GpkClientDialogWidgets:
+ * GpkModalDialogWidgets:
  */
 typedef enum
 {

Modified: trunk/src/gpk-watch.c
==============================================================================
--- trunk/src/gpk-watch.c	(original)
+++ trunk/src/gpk-watch.c	Tue Apr 14 16:28:59 2009
@@ -46,7 +46,7 @@
 #include "gpk-common.h"
 #include "gpk-error.h"
 #include "gpk-watch.h"
-#include "gpk-client.h"
+#include "gpk-modal-dialog.h"
 #include "gpk-inhibit.h"
 #include "gpk-smart-icon.h"
 #include "gpk-consolekit.h"
@@ -68,13 +68,12 @@
 	GPtrArray		*restart_package_names;
 	NotifyNotification	*notification_cached_messages;
 	GpkInhibit		*inhibit;
-	GpkClient		*gclient;
-	GpkClient		*monitor;
+	GpkModalDialog		*dialog;
+	PkClient		*client_primary;
 	PkConnection		*pconnection;
 	PkTaskList		*tlist;
 	PkRestartEnum		 restart;
 	GConfClient		*gconf_client;
-	gboolean		 show_refresh_in_menu;
 	PolKitGnomeAction	*restart_action;
 	guint			 set_proxy_timeout;
 	gchar			*error_details;
@@ -339,13 +338,6 @@
 {
 	g_return_if_fail (GPK_IS_WATCH (watch));
 
-	if (pk_task_list_contains_role (tlist, PK_ROLE_ENUM_REFRESH_CACHE) ||
-	    pk_task_list_contains_role (tlist, PK_ROLE_ENUM_UPDATE_PACKAGES) ||
-	    pk_task_list_contains_role (tlist, PK_ROLE_ENUM_UPDATE_SYSTEM))
-		watch->priv->show_refresh_in_menu = FALSE;
-	else
-		watch->priv->show_refresh_in_menu = TRUE;
-
 	gpk_watch_refresh_icon (watch);
 	gpk_watch_refresh_tooltip (watch);
 }
@@ -372,10 +364,10 @@
 }
 
 /**
- * gpk_watch_finished_cb:
+ * gpk_watch_task_list_finished_cb:
  **/
 static void
-gpk_watch_finished_cb (PkTaskList *tlist, PkClient *client, PkExitEnum exit_enum, guint runtime, GpkWatch *watch)
+gpk_watch_task_list_finished_cb (PkTaskList *tlist, PkClient *client, PkExitEnum exit_enum, guint runtime, GpkWatch *watch)
 {
 	guint i;
 	gboolean ret;
@@ -793,27 +785,6 @@
 }
 
 /**
- * gpk_watch_menu_refresh_cache_cb:
- **/
-static void
-gpk_watch_menu_refresh_cache_cb (GtkMenuItem *item, gpointer data)
-{
-	gboolean ret;
-	GpkWatch *watch = GPK_WATCH (data);
-	GError *error = NULL;
-
-	g_return_if_fail (GPK_IS_WATCH (watch));
-
-	egg_debug ("refresh cache");
-	gpk_client_set_interaction (watch->priv->gclient, GPK_CLIENT_INTERACT_ALWAYS);
-	ret = gpk_client_refresh_cache (watch->priv->gclient, &error);
-	if (!ret) {
-		egg_warning ("%s", error->message);
-		g_error_free (error);
-	}
-}
-
-/**
  * gpk_watch_menu_show_messages_cb:
  **/
 static void
@@ -930,6 +901,214 @@
 }
 
 /**
+ * gpk_watch_get_role_text:
+ **/
+static gchar *
+gpk_watch_get_role_text (PkClient *client)
+{
+	const gchar *role_text;
+	gchar *text;
+	gchar *message;
+	PkRoleEnum role;
+	GError *error = NULL;
+	gboolean ret;
+
+	/* get role and text */
+	ret = pk_client_get_role (client, &role, &text, &error);
+	if (!ret) {
+		egg_warning ("failed to get role: %s", error->message);
+		g_error_free (error);
+		return NULL;
+	}
+
+	/* backup */
+	role_text = gpk_role_enum_to_localised_present (role);
+
+	if (!egg_strzero (text) && role != PK_ROLE_ENUM_UPDATE_PACKAGES)
+		message = g_strdup_printf ("%s: %s", role_text, text);
+	else
+		message = g_strdup_printf ("%s", role_text);
+	g_free (text);
+
+	return message;
+}
+
+/**
+ * gpk_watch_progress_changed_cb:
+ **/
+static void
+gpk_watch_progress_changed_cb (PkClient *client, guint percentage, guint subpercentage,
+				guint elapsed, guint remaining, GpkWatch *watch)
+{
+	gpk_modal_dialog_set_percentage (watch->priv->dialog, percentage);
+	gpk_modal_dialog_set_remaining (watch->priv->dialog, remaining);
+}
+
+/**
+ * gpk_watch_set_status:
+ **/
+static gboolean
+gpk_watch_set_status (GpkWatch *watch, PkStatusEnum status)
+{
+	/* do we force progress? */
+	if (status == PK_STATUS_ENUM_DOWNLOAD_REPOSITORY ||
+	    status == PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST ||
+	    status == PK_STATUS_ENUM_DOWNLOAD_FILELIST ||
+	    status == PK_STATUS_ENUM_DOWNLOAD_CHANGELOG ||
+	    status == PK_STATUS_ENUM_DOWNLOAD_GROUP ||
+	    status == PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO ||
+	    status == PK_STATUS_ENUM_REFRESH_CACHE) {
+		gpk_modal_dialog_setup (watch->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	}
+
+	/* set icon */
+	gpk_modal_dialog_set_image_status (watch->priv->dialog, status);
+
+	/* set label */
+	gpk_modal_dialog_set_title (watch->priv->dialog, gpk_status_enum_to_localised_text (status));
+
+	/* spin */
+	if (status == PK_STATUS_ENUM_WAIT)
+		gpk_modal_dialog_set_percentage (watch->priv->dialog, PK_CLIENT_PERCENTAGE_INVALID);
+
+	/* do visual stuff when finished */
+	if (status == PK_STATUS_ENUM_FINISHED) {
+		/* make insensitive */
+		gpk_modal_dialog_set_allow_cancel (watch->priv->dialog, FALSE);
+
+		/* stop spinning */
+		gpk_modal_dialog_set_percentage (watch->priv->dialog, 100);
+	}
+	return TRUE;
+}
+
+/**
+ * gpk_watch_status_changed_cb:
+ **/
+static void
+gpk_watch_status_changed_cb (PkClient *client, PkStatusEnum status, GpkWatch *watch)
+{
+	gpk_watch_set_status (watch, status);
+}
+
+/**
+ * gpk_watch_package_cb:
+ **/
+static void
+gpk_watch_package_cb (PkClient *client, const PkPackageObj *obj, GpkWatch *watch)
+{
+	gchar *text;
+	text = gpk_package_id_format_twoline (obj->id, obj->summary);
+	gpk_modal_dialog_set_message (watch->priv->dialog, text);
+	g_free (text);
+}
+
+/**
+ * gpk_watch_monitor_tid:
+ **/
+static gboolean
+gpk_watch_monitor_tid (GpkWatch *watch, const gchar *tid)
+{
+	PkStatusEnum status;
+	gboolean ret;
+	gboolean allow_cancel;
+	gchar *text;
+	gchar *package_id = NULL;
+	guint percentage;
+	guint subpercentage;
+	guint elapsed;
+	guint remaining;
+	GError *error = NULL;
+	PkRoleEnum role;
+
+	/* reset client */
+	ret = pk_client_reset (watch->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to reset client: %s", error->message);
+		g_error_free (error);
+		return FALSE;
+	}
+
+	ret = pk_client_set_tid (watch->priv->client_primary, tid, &error);
+	if (!ret) {
+		egg_warning ("could not set tid: %s", error->message);
+		g_error_free (error);
+		return FALSE;
+	}
+
+	/* fill in role */
+	text = gpk_watch_get_role_text (watch->priv->client_primary);
+	gpk_modal_dialog_set_title (watch->priv->dialog, text);
+	g_free (text);
+
+	/* coldplug */
+	ret = pk_client_get_status (watch->priv->client_primary, &status, NULL);
+	/* no such transaction? */
+	if (!ret) {
+		egg_warning ("could not get status");
+		return FALSE;
+	}
+
+	/* are we cancellable? */
+	pk_client_get_allow_cancel (watch->priv->client_primary, &allow_cancel, NULL);
+	gpk_modal_dialog_set_allow_cancel (watch->priv->dialog, allow_cancel);
+
+	/* coldplug */
+	ret = pk_client_get_progress (watch->priv->client_primary,
+				      &percentage, &subpercentage, &elapsed, &remaining, NULL);
+	if (ret) {
+		gpk_watch_progress_changed_cb (watch->priv->client_primary, percentage,
+						subpercentage, elapsed, remaining, watch);
+	} else {
+		egg_warning ("GetProgress failed");
+		gpk_watch_progress_changed_cb (watch->priv->client_primary,
+						PK_CLIENT_PERCENTAGE_INVALID,
+						PK_CLIENT_PERCENTAGE_INVALID, 0, 0, watch);
+	}
+
+	/* get the role */
+	ret = pk_client_get_role (watch->priv->client_primary, &role, NULL, &error);
+	if (!ret) {
+		egg_warning ("failed to get role: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* setup the UI */
+	if (role == PK_ROLE_ENUM_SEARCH_NAME ||
+	    role == PK_ROLE_ENUM_SEARCH_GROUP ||
+	    role == PK_ROLE_ENUM_SEARCH_DETAILS ||
+	    role == PK_ROLE_ENUM_SEARCH_FILE ||
+	    role == PK_ROLE_ENUM_SEARCH_NAME ||
+	    role == PK_ROLE_ENUM_GET_UPDATES)
+		gpk_modal_dialog_setup (watch->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	else
+		gpk_modal_dialog_setup (watch->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+
+	/* set the status */
+	gpk_watch_set_status (watch, status);
+
+	/* do the best we can, and get the last package */
+	ret = pk_client_get_package (watch->priv->client_primary, &package_id, NULL);
+	if (ret) {
+		PkPackageId *id;
+		PkPackageObj *obj;
+
+		id = pk_package_id_new_from_string (package_id);
+		if (id != NULL) {
+			obj = pk_package_obj_new (PK_INFO_ENUM_UNKNOWN, id, NULL);
+			egg_warning ("package_id=%s", package_id);
+			gpk_watch_package_cb (watch->priv->client_primary, obj, watch);
+			pk_package_obj_free (obj);
+		}
+		pk_package_id_free (id);
+	}
+
+	gpk_modal_dialog_present (watch->priv->dialog);
+
+	return TRUE;
+}
+
+/**
  * gpk_watch_menu_job_status_cb:
  **/
 static void
@@ -947,7 +1126,7 @@
 	}
 
 	/* launch the UI */
-	gpk_client_monitor_tid (watch->priv->monitor, tid);
+	gpk_watch_monitor_tid (watch, tid);
 }
 
 /**
@@ -1050,24 +1229,6 @@
 	/* add jobs as drop down */
 	len = gpk_watch_populate_menu_with_jobs (watch, menu);
 
-	/* force a refresh if we are not updating or refreshing */
-	if (watch->priv->show_refresh_in_menu) {
-
-		/* Separator for HIG? */
-		if (len > 0) {
-			widget = gtk_separator_menu_item_new ();
-			gtk_menu_shell_append (GTK_MENU_SHELL (menu), widget);
-		}
-
-		/* TRANSLATORS: This is a right click menu item, and will refresh all the package lists */
-		widget = gtk_image_menu_item_new_with_mnemonic (_("_Refresh Software List"));
-		image = gtk_image_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_MENU);
-		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
-		g_signal_connect (G_OBJECT (widget), "activate",
-				  G_CALLBACK (gpk_watch_menu_refresh_cache_cb), watch);
-		gtk_menu_shell_append (GTK_MENU_SHELL (menu), widget);
-	}
-
 	/* any messages to show? */
 	len = watch->priv->cached_messages->len;
 	if (len > 0) {
@@ -1328,6 +1489,59 @@
 }
 
 /**
+ * gpk_watch_allow_cancel_cb:
+ **/
+static void
+gpk_watch_allow_cancel_cb (PkClient *client, gboolean allow_cancel, GpkWatch *watch)
+{
+	gpk_modal_dialog_set_allow_cancel (watch->priv->dialog, allow_cancel);
+}
+
+/**
+ * gpk_watch_finished_cb:
+ **/
+static void
+gpk_watch_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkWatch *watch)
+{
+	g_return_if_fail (GPK_IS_WATCH (watch));
+
+	/* stop spinning */
+	gpk_modal_dialog_set_percentage (watch->priv->dialog, 100);
+
+	/* autoclose if success */
+	if (exit_enum == PK_EXIT_ENUM_SUCCESS) {
+		gpk_modal_dialog_close (watch->priv->dialog);
+	}
+}
+
+/**
+ * gpk_watch_button_close_cb:
+ **/
+static void
+gpk_watch_button_close_cb (GtkWidget *widget, GpkWatch *watch)
+{
+	/* close, don't abort */
+	gpk_modal_dialog_close (watch->priv->dialog);
+}
+
+/**
+ * gpk_watch_button_cancel_cb:
+ **/
+static void
+gpk_watch_button_cancel_cb (GtkWidget *widget, GpkWatch *watch)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* we might have a transaction running */
+	ret = pk_client_cancel (watch->priv->client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to cancel client: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+/**
  * gpk_watch_init:
  * @watch: This class instance
  **/
@@ -1343,17 +1557,31 @@
 	watch->priv->notification_cached_messages = NULL;
 	watch->priv->restart = PK_RESTART_ENUM_NONE;
 
-	watch->priv->show_refresh_in_menu = TRUE;
 	watch->priv->gconf_client = gconf_client_get_default ();
 
 	watch->priv->sicon = gpk_smart_icon_new ();
 	watch->priv->set_proxy_timeout = 0;
-	watch->priv->gclient = gpk_client_new ();
 	watch->priv->cached_messages = g_ptr_array_new ();
 	watch->priv->restart_package_names = g_ptr_array_new ();
 
-	watch->priv->monitor = gpk_client_new ();
-	gpk_client_set_interaction (watch->priv->monitor, GPK_CLIENT_INTERACT_WARNING_PROGRESS);
+	watch->priv->client_primary = pk_client_new ();
+	g_signal_connect (watch->priv->client_primary, "finished",
+			  G_CALLBACK (gpk_watch_finished_cb), watch);
+	g_signal_connect (watch->priv->client_primary, "progress-changed",
+			  G_CALLBACK (gpk_watch_progress_changed_cb), watch);
+	g_signal_connect (watch->priv->client_primary, "status-changed",
+			  G_CALLBACK (gpk_watch_status_changed_cb), watch);
+	g_signal_connect (watch->priv->client_primary, "package",
+			  G_CALLBACK (gpk_watch_package_cb), watch);
+	g_signal_connect (watch->priv->client_primary, "allow-cancel",
+			  G_CALLBACK (gpk_watch_allow_cancel_cb), watch);
+
+	watch->priv->dialog = gpk_modal_dialog_new ();
+	gpk_modal_dialog_set_window_icon (watch->priv->dialog, "pk-package-installed");
+	g_signal_connect (watch->priv->dialog, "cancel",
+			  G_CALLBACK (gpk_watch_button_cancel_cb), watch);
+	g_signal_connect (watch->priv->dialog, "close",
+			  G_CALLBACK (gpk_watch_button_close_cb), watch);
 
 	/* we need to get ::locked */
 	watch->priv->control = pk_control_new ();
@@ -1376,7 +1604,7 @@
 	g_signal_connect (watch->priv->tlist, "status-changed",
 			  G_CALLBACK (gpk_watch_task_list_changed_cb), watch);
 	g_signal_connect (watch->priv->tlist, "finished",
-			  G_CALLBACK (gpk_watch_finished_cb), watch);
+			  G_CALLBACK (gpk_watch_task_list_finished_cb), watch);
 	g_signal_connect (watch->priv->tlist, "error-code",
 			  G_CALLBACK (gpk_watch_error_code_cb), watch);
 	g_signal_connect (watch->priv->tlist, "message",
@@ -1451,11 +1679,11 @@
 	g_object_unref (watch->priv->inhibit);
 	g_object_unref (watch->priv->tlist);
 	g_object_unref (watch->priv->control);
-	g_object_unref (watch->priv->gclient);
 	g_object_unref (watch->priv->pconnection);
 	g_object_unref (watch->priv->gconf_client);
 	g_object_unref (watch->priv->restart_action);
-	g_object_unref (watch->priv->monitor);
+	g_object_unref (watch->priv->client_primary);
+	g_object_unref (watch->priv->dialog);
 
 	G_OBJECT_CLASS (gpk_watch_parent_class)->finalize (object);
 }

Modified: trunk/src/org.freedesktop.PackageKit.xml
==============================================================================
--- trunk/src/org.freedesktop.PackageKit.xml	(original)
+++ trunk/src/org.freedesktop.PackageKit.xml	Tue Apr 14 16:28:59 2009
@@ -5,7 +5,6 @@
 ]>
 <node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd";>
 
-  <!-- ######################################################################################### -->
   <interface name="org.freedesktop.PackageKit.Query">
     <doc:doc>
       <doc:description>
@@ -17,6 +16,7 @@
 
     <!--*****************************************************************************************-->
     <method name="IsInstalled">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
       <doc:doc>
         <doc:description>
           <doc:para>
@@ -56,6 +56,7 @@
 
     <!--*****************************************************************************************-->
     <method name="SearchFile">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
       <doc:doc>
         <doc:description>
           <doc:para>
@@ -362,64 +363,5 @@
       </arg>
     </method>
   </interface>
-
-  <!-- ######################################################################################### -->
-  <!-- LEGACY INTERFACE -->
-  <interface name="org.freedesktop.PackageKit">
-<!--
-    <method name="IsPackageInstalled">
-      <arg type="s" name="package_name" direction="in"/>
-      <arg type="b" name="installed" direction="out"/>
-    </method>
--->
-    <method name="InstallLocalFile">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="full_path" direction="in"/>
-    </method>
-    <method name="InstallProvideFile">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="full_path" direction="in"/>
-    </method>
-    <method name="InstallPackageName">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="package_name" direction="in"/>
-    </method>
-    <method name="InstallMimeType">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="mime_type" direction="in"/>
-    </method>
-    <method name="InstallGStreamerCodecs">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="a(ss)" name="codecs" direction="in"/>
-    </method>
-    <method name="InstallFont">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="font_desc" direction="in"/>
-    </method>
-    <method name="InstallFonts">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="as" name="font_descs" direction="in"/>
-    </method>
-    <method name="InstallCatalog">
-      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
-      <arg type="u" name="xid" direction="in"/>
-      <arg type="u" name="timestamp" direction="in"/>
-      <arg type="s" name="catalog_file" direction="in"/>
-    </method>
-  </interface>
 </node>
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]