gnome-packagekit r507 - in trunk: . data po src



Author: rhughes
Date: Sun Mar 15 12:31:27 2009
New Revision: 507
URL: http://svn.gnome.org/viewvc/gnome-packagekit?rev=507&view=rev

Log:
from git

Added:
   trunk/src/gpk-eula-helper.c
   trunk/src/gpk-eula-helper.h
   trunk/src/gpk-repo-signature-helper.c
   trunk/src/gpk-repo-signature-helper.h
   trunk/src/gpk-update-viewer2.c
Modified:
   trunk/NEWS
   trunk/configure.ac
   trunk/data/Makefile.am
   trunk/data/gpk-install-catalog.desktop.in
   trunk/po/POTFILES.in
   trunk/src/.gitignore
   trunk/src/Makefile.am
   trunk/src/gpk-animated-icon.c
   trunk/src/gpk-cell-renderer-info.c
   trunk/src/gpk-cell-renderer-info.h
   trunk/src/gpk-cell-renderer-percentage.c
   trunk/src/gpk-common.c
   trunk/src/gpk-common.h
   trunk/src/gpk-enum.c
   trunk/src/gpk-error.c
   trunk/src/gpk-marshal.list
   trunk/src/gpk-repo.c

Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS	(original)
+++ trunk/NEWS	Sun Mar 15 12:31:27 2009
@@ -1,3 +1,26 @@
+Version 0.4.5
+~~~~~~~~~~~~~
+Released: 2000-03-09
+
+* Translations
+ - Updated Portuguese translation (AntÃnio Lima)
+ - Updated Spanish translation (Daniel Mustieles, Jorge Gonzalez)
+ - Updated Swedish translation (Daniel Nylander)
+ - Updated Brazilian Portuguese translation (Igor Soares)
+ - Updated Norwegian bokmÃl translation (Kjartan Maraas)
+ - Updated Dutch translation (Reinout van Schouwen)
+ - Updated Polish translation (Tomasz Dominikowski)
+ - Updated Finnish translation (Ville-Pekka Vainio)
+
+* New Features:
+ - Merge in a new update viewer with a very different UI (Richard Hughes)
+
+* Bugfix:
+ - Allow markup in the error dialog message (Richard Hughes)
+ - Disable the polling in GpkAnimatedIcon if the widget is disabled (Richard Hughes)
+ - Don't check for local for all the GUI tools, so we can use vncviewer (Richard Hughes)
+ - Correct some of the strings we show the user about the restart mode (Richard Hughes)
+
 Version 0.4.4
 ~~~~~~~~~~~~~
 Released: 2000-02-23

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Sun Mar 15 12:31:27 2009
@@ -1,6 +1,6 @@
 AC_PREREQ(2.52)
 
-AC_INIT(gnome-packagekit, 0.4.5)
+AC_INIT(gnome-packagekit, 0.4.6)
 AC_CONFIG_SRCDIR(src)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 AM_CONFIG_HEADER(config.h)

Modified: trunk/data/Makefile.am
==============================================================================
--- trunk/data/Makefile.am	(original)
+++ trunk/data/Makefile.am	Sun Mar 15 12:31:27 2009
@@ -32,6 +32,7 @@
 	gpk-eula.glade					\
 	gpk-application.glade				\
 	gpk-update-viewer.glade				\
+	gpk-update-viewer2.glade			\
 	gpk-prefs.glade					\
 	gpk-service-pack.glade				\
 	gpk-signature.glade				\

Modified: trunk/data/gpk-install-catalog.desktop.in
==============================================================================
--- trunk/data/gpk-install-catalog.desktop.in	(original)
+++ trunk/data/gpk-install-catalog.desktop.in	Sun Mar 15 12:31:27 2009
@@ -10,5 +10,5 @@
 Icon=system-software-install
 StartupNotify=true
 NoDisplay=true
-MimeType=application/x-catalog
+MimeType=application/x-catalog;
 

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Sun Mar 15 12:31:27 2009
@@ -22,6 +22,7 @@
 data/gpk-update-icon.desktop.in
 data/gpk-update-viewer.desktop.in
 data/gpk-update-viewer.glade
+data/gpk-update-viewer2.glade
 src/gpk-application.c
 src/gpk-application-main.c
 src/gpk-backend-status.c
@@ -55,5 +56,6 @@
 src/gpk-update-viewer.c
 src/gpk-watch.c
 src/gpk-desktop.c
+src/gpk-update-viewer2.c
 python/packagekit/gtkwidgets.py
 

Modified: trunk/src/.gitignore
==============================================================================
--- trunk/src/.gitignore	(original)
+++ trunk/src/.gitignore	Sun Mar 15 12:31:27 2009
@@ -23,6 +23,7 @@
 gpk-install-catalog
 gpk-prefs
 gpk-update-viewer
+gpk-update-viewer2
 gpk-backend-status
 gpk-self-test
 gpk-service-pack

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Sun Mar 15 12:31:27 2009
@@ -42,6 +42,7 @@
 	gpk-install-package-name			\
 	gpk-update-icon					\
 	gpk-update-viewer				\
+	gpk-update-viewer2				\
 	gpk-log						\
 	gpk-backend-status				\
 	$(NULL)
@@ -207,21 +208,37 @@
 	$(NULL)
 
 gpk_prefs_SOURCES =					\
-	egg-debug.c					\
-	egg-debug.h					\
-	egg-unique.c					\
-	egg-unique.h					\
 	gpk-prefs.c					\
-	gpk-gnome.c					\
-	gpk-gnome.h					\
-	gpk-enum.c					\
-	gpk-enum.h					\
+	$(shared_SOURCES)				\
 	$(NULL)
 
 gpk_prefs_LDADD =					\
 	$(shared_LIBS)					\
 	$(NULL)
 
+gpk_update_viewer2_SOURCES =				\
+	gpk-update-viewer2.c				\
+	gpk-repo-signature-helper.c			\
+	gpk-repo-signature-helper.h			\
+	gpk-eula-helper.c				\
+	gpk-eula-helper.h				\
+	gpk-cell-renderer-uri.c				\
+	gpk-cell-renderer-uri.h				\
+	gpk-cell-renderer-size.c			\
+	gpk-cell-renderer-size.h			\
+	gpk-cell-renderer-info.c			\
+	gpk-cell-renderer-info.h			\
+	gpk-cell-renderer-percentage.c			\
+	gpk-cell-renderer-percentage.h			\
+	gpk-cell-renderer-restart.c			\
+	gpk-cell-renderer-restart.h			\
+	$(shared_SOURCES)				\
+	$(NULL)
+
+gpk_update_viewer2_LDADD =				\
+	$(shared_LIBS)					\
+	$(NULL)
+
 gpk_update_viewer_SOURCES =				\
 	gpk-update-viewer.c				\
 	gpk-cell-renderer-uri.c				\

Modified: trunk/src/gpk-animated-icon.c
==============================================================================
--- trunk/src/gpk-animated-icon.c	(original)
+++ trunk/src/gpk-animated-icon.c	Sun Mar 15 12:31:27 2009
@@ -142,6 +142,21 @@
 	return TRUE;
 }
 
+
+/**
+ * gpk_animated_icon_visible_notify_cb:
+ **/
+static void
+gpk_animated_icon_visible_notify_cb (GObject *object, GParamSpec *param, GpkAnimatedIcon *icon)
+{
+	gboolean ret;
+	g_object_get (object, "visible", &ret, NULL);
+	if (!ret && icon->animation_id != 0) {
+		egg_debug ("disabling animation as hidden");
+		gpk_animated_icon_enable_animation (icon, FALSE);
+	}
+}
+
 /**
  * gpk_animated_icon_update:
  **/
@@ -266,6 +281,9 @@
 	icon->frame_counter = 0;
 	icon->number_frames = 0;
 	icon->frame_delay = 200;
+
+	/* disable polling if we are hidden */
+	g_signal_connect (GTK_WIDGET (icon), "notify::visible", G_CALLBACK (gpk_animated_icon_visible_notify_cb), icon);
 }
 
 /**

Modified: trunk/src/gpk-cell-renderer-info.c
==============================================================================
--- trunk/src/gpk-cell-renderer-info.c	(original)
+++ trunk/src/gpk-cell-renderer-info.c	Sun Mar 15 12:31:27 2009
@@ -36,19 +36,27 @@
 	PROP_VALUE
 };
 
+#define GPK_CELL_RENDERER_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GPK_TYPE_CELL_RENDERER_INFO, GpkCellRendererInfoPrivate))
+
+struct _GpkCellRendererInfoPrivate
+{
+	PkInfoEnum		 value;
+	const gchar		*icon_name;
+};
+
 G_DEFINE_TYPE (GpkCellRendererInfo, gpk_cell_renderer_info, GTK_TYPE_CELL_RENDERER_PIXBUF)
 
 static gpointer parent_class = NULL;
 
 static void
 gpk_cell_renderer_info_get_property (GObject *object, guint param_id,
-				        GValue *value, GParamSpec *pspec)
+				     GValue *value, GParamSpec *pspec)
 {
 	GpkCellRendererInfo *cru = GPK_CELL_RENDERER_INFO (object);
 
 	switch (param_id) {
 	case PROP_VALUE:
-		g_value_set_uint (value, cru->value);
+		g_value_set_uint (value, cru->priv->value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -58,15 +66,21 @@
 
 static void
 gpk_cell_renderer_info_set_property (GObject *object, guint param_id,
-				    const GValue *value, GParamSpec *pspec)
+				     const GValue *value, GParamSpec *pspec)
 {
 	GpkCellRendererInfo *cru = GPK_CELL_RENDERER_INFO (object);
 
 	switch (param_id) {
 	case PROP_VALUE:
-		cru->value = g_value_get_uint (value);
-		cru->icon_name = gpk_info_enum_to_icon_name (cru->value);
-		g_object_set (cru, "icon-name", cru->icon_name, NULL);
+		cru->priv->value = g_value_get_uint (value);
+		if (cru->priv->value == PK_INFO_ENUM_UNKNOWN ||
+		    cru->priv->value == PK_INFO_ENUM_FINISHED) {
+			g_object_set (cru, "visible", FALSE, NULL);
+		} else {
+			cru->priv->icon_name = gpk_info_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;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -103,6 +117,8 @@
 	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_type_class_add_private (object_class, sizeof (GpkCellRendererInfoPrivate));
 }
 
 /**
@@ -111,8 +127,9 @@
 static void
 gpk_cell_renderer_info_init (GpkCellRendererInfo *cru)
 {
-	cru->value = PK_INFO_ENUM_UNKNOWN;
-	cru->icon_name = NULL;
+	cru->priv = GPK_CELL_RENDERER_INFO_GET_PRIVATE (cru);
+	cru->priv->value = PK_INFO_ENUM_UNKNOWN;
+	cru->priv->icon_name = NULL;
 }
 
 /**

Modified: trunk/src/gpk-cell-renderer-info.h
==============================================================================
--- trunk/src/gpk-cell-renderer-info.h	(original)
+++ trunk/src/gpk-cell-renderer-info.h	Sun Mar 15 12:31:27 2009
@@ -37,12 +37,12 @@
 
 typedef struct _GpkCellRendererInfo		GpkCellRendererInfo;
 typedef struct _GpkCellRendererInfoClass	GpkCellRendererInfoClass;
+typedef struct _GpkCellRendererInfoPrivate	GpkCellRendererInfoPrivate;
 
 struct _GpkCellRendererInfo
 {
-	GtkCellRendererPixbuf	 parent;
-	PkInfoEnum		 value;
-	const gchar		*icon_name;
+	GtkCellRendererPixbuf		 parent;
+	GpkCellRendererInfoPrivate	*priv;
 };
 
 struct _GpkCellRendererInfoClass

Modified: trunk/src/gpk-cell-renderer-percentage.c
==============================================================================
--- trunk/src/gpk-cell-renderer-percentage.c	(original)
+++ trunk/src/gpk-cell-renderer-percentage.c	Sun Mar 15 12:31:27 2009
@@ -65,7 +65,7 @@
 	switch (param_id) {
 	case PROP_PERCENT:
 		cru->percent = g_value_get_uint (value);
-		if (cru->percent == 0) {
+		if (cru->percent == 0 || cru->percent == 100) {
 			g_object_set (cru, "pulse", -1, NULL);
 			g_object_set (cru, "visible", FALSE, NULL);
 		} else if (cru->percent == 101) {
@@ -122,7 +122,7 @@
 {
 	cru->percent = 0;
 	g_object_set (cru, "text", "", NULL);
-	g_object_set (cru, "ypad", 6, NULL);
+	g_object_set (cru, "ypad", 8, NULL);
 }
 
 /**

Modified: trunk/src/gpk-common.c
==============================================================================
--- trunk/src/gpk-common.c	(original)
+++ trunk/src/gpk-common.c	Sun Mar 15 12:31:27 2009
@@ -45,6 +45,132 @@
 #define GNOME_SESSION_MANAGER_PATH		"/org/gnome/SessionManager"
 #define GNOME_SESSION_MANAGER_INTERFACE		"org.gnome.SessionManager"
 
+
+/**
+ * gtk_text_buffer_set_markup:
+ * @buffer: a #GtkTextBuffer
+ * @markup: nul-terminated UTF-8 text with pango markup to insert
+ **/
+void
+gtk_text_buffer_set_markup (GtkTextBuffer *buffer, const gchar *markup)
+{
+	GtkTextIter textiter, end_iter;
+	PangoAttrIterator *paiter;
+	PangoAttrList *attrlist;
+	GtkTextMark *mark;
+	GError *error = NULL;
+	gchar *text;
+
+	g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+	g_return_if_fail (markup != NULL);
+
+	if (*markup == '\000')
+		return;
+
+	gtk_text_buffer_get_bounds (buffer, &textiter, &end_iter);
+	gtk_text_buffer_delete (buffer, &textiter, &end_iter);
+	gtk_text_buffer_get_iter_at_offset (buffer, &textiter, 0);
+
+	/* invalid */
+	if (!pango_parse_markup (markup, -1, 0, &attrlist, &text, NULL, &error)) {
+		g_warning ("Invalid markup string: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* trivial, no markup */
+	if (attrlist == NULL) {
+		gtk_text_buffer_insert (buffer, &textiter, text, -1);
+		g_free (text);
+		return;
+	}
+
+	/* create mark with right gravity */
+	mark = gtk_text_buffer_create_mark (buffer, NULL, &textiter, FALSE);
+	paiter = pango_attr_list_get_iterator (attrlist);
+
+	do {
+		PangoAttribute *attr;
+		GtkTextTag *tag;
+		gint start, end;
+
+		pango_attr_iterator_range (paiter, &start, &end);
+
+		if (end == G_MAXINT)	/* last chunk */
+			end = start-1; /* resulting in -1 to be passed to _insert */
+
+		tag = gtk_text_tag_new (NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_LANGUAGE)))
+			g_object_set (tag, "language", pango_language_to_string ( ( (PangoAttrLanguage*)attr)->value), NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_FAMILY)))
+			g_object_set (tag, "family", ( (PangoAttrString*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_STYLE)))
+			g_object_set (tag, "style", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_WEIGHT)))
+			g_object_set (tag, "weight", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_VARIANT)))
+			g_object_set (tag, "variant", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_STRETCH)))
+			g_object_set (tag, "stretch", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_SIZE)))
+			g_object_set (tag, "size", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_FONT_DESC)))
+			g_object_set (tag, "font-desc", ( (PangoAttrFontDesc*)attr)->desc, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_FOREGROUND))) {
+			GdkColor col = { 0,
+					( (PangoAttrColor*)attr)->color.red,
+					( (PangoAttrColor*)attr)->color.green,
+					( (PangoAttrColor*)attr)->color.blue
+					};
+
+			g_object_set (tag, "foreground-gdk", &col, NULL);
+		}
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_BACKGROUND))) {
+			GdkColor col = { 0,
+					( (PangoAttrColor*)attr)->color.red,
+					( (PangoAttrColor*)attr)->color.green,
+					( (PangoAttrColor*)attr)->color.blue
+					};
+
+			g_object_set (tag, "background-gdk", &col, NULL);
+		}
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_UNDERLINE)))
+			g_object_set (tag, "underline", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_STRIKETHROUGH)))
+			g_object_set (tag, "strikethrough", (gboolean) ( ( (PangoAttrInt*)attr)->value != 0), NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_RISE)))
+			g_object_set (tag, "rise", ( (PangoAttrInt*)attr)->value, NULL);
+
+		if ( (attr = pango_attr_iterator_get (paiter, PANGO_ATTR_SCALE)))
+			g_object_set (tag, "scale", ( (PangoAttrFloat*)attr)->value, NULL);
+
+		gtk_text_tag_table_add (gtk_text_buffer_get_tag_table (buffer), tag);
+		gtk_text_buffer_insert_with_tags (buffer, &textiter, text+start, end - start, tag, NULL);
+
+		/* mark had right gravity, so it should be
+		 *	at the end of the inserted text now */
+		gtk_text_buffer_get_iter_at_mark (buffer, &textiter, mark);
+	} while (pango_attr_iterator_next (paiter));
+
+	gtk_text_buffer_delete_mark (buffer, mark);
+	pango_attr_iterator_destroy (paiter);
+	pango_attr_list_unref (attrlist);
+	g_free (text);
+}
+
 /**
  * gpk_session_logout:
  **/
@@ -217,11 +343,10 @@
 gboolean
 gpk_check_privileged_user (const gchar *application_name, gboolean show_ui)
 {
-	EggConsoleKit *ck = NULL;
 	guint uid;
-	gboolean ret = FALSE;
-	gchar *message;
-	gchar *title;
+	gboolean ret = TRUE;
+	gchar *message = NULL;
+	gchar *title = NULL;
 	GtkResponseType result;
 	GtkWidget *dialog;
 
@@ -251,67 +376,16 @@
 		result = gtk_dialog_run (GTK_DIALOG(dialog));
 		gtk_widget_destroy (dialog);
 
-		g_free (title);
-		g_free (message);
-
 		/* user did not agree to run insecure */
 		if (result != GTK_RESPONSE_OK) {
+			ret = FALSE;
 			egg_warning ("uid=%i so closing", uid);
 			goto out;
 		}
 	}
-
-	/* talk to ConsoleKit */
-	ck = egg_console_kit_new ();
-
-	/* we are not local */
-	ret = egg_console_kit_is_local (ck);
-	if (!ret) {
-		if (!show_ui)
-			goto out;
-		if (application_name == NULL)
-			/* TRANSLATORS: the user is not sitting in front of the keyboard */
-			title = g_strdup (_("This application is running when the session is not local"));
-		else
-			/* TRANSLATORS: same, but we know the application name */
-			title = g_strdup_printf (_("%s is running when the session is not local"), application_name);
-		message = g_strjoin ("\n",
-				     /* TRANSLATORS: tell the user off */
-				     _("These applications should be run only when on local console."),
-				     /* TRANSLATORS: explain what to do */
-				     _("This normally indicates a bug with ConsoleKit or with the way your session has started."), NULL);
-		gpk_error_dialog (title, message, "");
-		g_free (title);
-		g_free (message);
-		egg_warning ("not LOCAL so closing");
-		goto out;
-	}
-
-	/* we are not active */
-	ret = egg_console_kit_is_active (ck);
-	if (!ret) {
-		if (!show_ui)
-			goto out;
-		if (application_name == NULL)
-			/* TRANSLATORS: the user is not active, i.e. is idle */
-			title = g_strdup (_("This application is running when the session is not active"));
-		else
-			/* TRANSLATORS: same, but we know the application name */
-			title = g_strdup_printf (_("%s is running when the session is not active"), application_name);
-		message = g_strjoin ("\n",
-				     /* TRANSLATORS: tell the user off */
-				     _("These applications should be run only when on active console."),
-				     /* TRANSLATORS: explain what to do */
-				     _("This normally indicates a bug with your remote desktop implementation."), NULL);
-		gpk_error_dialog (title, message, "");
-		g_free (title);
-		g_free (message);
-		egg_warning ("not ACTIVE so closing");
-		goto out;
-	}
 out:
-	if (ck != NULL)
-		g_object_unref (ck);
+	g_free (title);
+	g_free (message);
 	return ret;
 }
 

Modified: trunk/src/gpk-common.h
==============================================================================
--- trunk/src/gpk-common.h	(original)
+++ trunk/src/gpk-common.h	Sun Mar 15 12:31:27 2009
@@ -82,6 +82,8 @@
 #define GPK_ICON_SERVICE_PACK			"gpk-service-pack"
 
 void		 gpk_common_test			(gpointer	 data);
+void		 gtk_text_buffer_set_markup		(GtkTextBuffer	*buffer,
+							 const gchar	*markup);
 gchar		*gpk_package_get_name			(const gchar	*package_id);
 gchar		*gpk_package_id_format_twoline		(const PkPackageId *id,
 							 const gchar	*summary);

Modified: trunk/src/gpk-enum.c
==============================================================================
--- trunk/src/gpk-enum.c	(original)
+++ trunk/src/gpk-enum.c	Sun Mar 15 12:31:27 2009
@@ -204,7 +204,7 @@
 static const PkEnumMatch enum_restart_icon_name[] = {
 	{PK_RESTART_ENUM_UNKNOWN,		"help-browser"},	/* fall though value */
 	{PK_RESTART_ENUM_NONE,			""},
-	{PK_RESTART_ENUM_SYSTEM,		"computer"},
+	{PK_RESTART_ENUM_SYSTEM,		"system-shutdown"},
 	{PK_RESTART_ENUM_SESSION,		"preferences-system-session"},
 	{PK_RESTART_ENUM_APPLICATION,		"emblem-symbolic-link"},
 	{0, NULL}
@@ -654,16 +654,16 @@
 	const gchar *text = NULL;
 	switch (restart) {
 	case PK_RESTART_ENUM_NONE:
-		text = _("No restart is necessary for this update");
+		text = _("No restart is necessary");
 		break;
 	case PK_RESTART_ENUM_APPLICATION:
-		text = _("An application restart is required after this update");
+		text = _("An application restart is required");
 		break;
 	case PK_RESTART_ENUM_SESSION:
-		text = _("You will be required to log off and back on after this update");
+		text = _("You will be required to log out and back in");
 		break;
 	case PK_RESTART_ENUM_SYSTEM:
-		text = _("A system restart is required after this update");
+		text = _("A restart is required");
 		break;
 	default:
 		egg_warning ("restart unrecognised: %i", restart);
@@ -683,7 +683,7 @@
 		text = _("No restart is required");
 		break;
 	case PK_RESTART_ENUM_SYSTEM:
-		text = _("A system restart is required");
+		text = _("A restart is required");
 		break;
 	case PK_RESTART_ENUM_SESSION:
 		text = _("You will need to log off and log back on");

Modified: trunk/src/gpk-error.c
==============================================================================
--- trunk/src/gpk-error.c	(original)
+++ trunk/src/gpk-error.c	Sun Mar 15 12:31:27 2009
@@ -108,7 +108,7 @@
 
 	/* message */
 	widget = glade_xml_get_widget (glade_xml, "label_message");
-	gtk_label_set_label (GTK_LABEL (widget), message);
+	gtk_label_set_markup (GTK_LABEL (widget), message);
 
 	/* show text in the expander */
 	if (egg_strzero (details)) {

Added: trunk/src/gpk-eula-helper.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-eula-helper.c	Sun Mar 15 12:31:27 2009
@@ -0,0 +1,233 @@
+/* -*- 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 <glade/glade.h>
+
+#include "gpk-eula-helper.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+
+#include "egg-debug.h"
+
+static void     gpk_eula_helper_finalize	(GObject	  *object);
+
+#define GPK_EULA_HELPER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_EULA_HELPER, GpkEulaHelperPrivate))
+
+struct GpkEulaHelperPrivate
+{
+	GladeXML		*glade_xml;
+	gchar			*eula_id;
+};
+
+enum {
+	GPK_EULA_HELPER_EVENT,
+	GPK_EULA_HELPER_LAST_SIGNAL
+};
+
+static guint signals [GPK_EULA_HELPER_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkEulaHelper, gpk_eula_helper, G_TYPE_OBJECT)
+
+/**
+ * gpk_eula_helper_button_agree_cb:
+ **/
+static void
+gpk_eula_helper_button_agree_cb (GtkWidget *widget, GpkEulaHelper *eula_helper)
+{
+	g_signal_emit (eula_helper, signals [GPK_EULA_HELPER_EVENT], 0, GTK_RESPONSE_YES, eula_helper->priv->eula_id);
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_eula_helper_button_cancel_cb:
+ **/
+static void
+gpk_eula_helper_button_cancel_cb (GtkWidget *widget, GpkEulaHelper *eula_helper)
+{
+	g_signal_emit (eula_helper, signals [GPK_EULA_HELPER_EVENT], 0, GTK_RESPONSE_NO, eula_helper->priv->eula_id);
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_eula_helper_button_help_cb:
+ **/
+static void
+gpk_eula_helper_button_help_cb (GtkWidget *widget, GpkEulaHelper *eula_helper)
+{
+	/* show the help */
+	gpk_gnome_help ("eula");
+}
+
+/**
+ * gpk_eula_helper_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_eula_helper_show (GpkEulaHelper *eula_helper, const gchar *eula_id, const gchar *package_id,
+	       const gchar *vendor_name, const gchar *license_agreement)
+{
+	GtkWidget *widget;
+	GtkTextBuffer *buffer;
+	gchar *text;
+	PkPackageId *ident;
+
+	g_return_val_if_fail (GPK_IS_EULA_HELPER (eula_helper), FALSE);
+	g_return_val_if_fail (eula_id != NULL, FALSE);
+
+	/* cache */
+	g_free (eula_helper->priv->eula_id);
+	eula_helper->priv->eula_id = g_strdup (eula_id);
+
+	/* title */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "label_title");
+	ident = pk_package_id_new_from_string (package_id);
+	text = g_strdup_printf ("<b><big>License required for %s by %s</big></b>", ident->name, vendor_name);
+	gtk_label_set_label (GTK_LABEL (widget), text);
+	pk_package_id_free (ident);
+	g_free (text);
+
+	buffer = gtk_text_buffer_new (NULL);
+	gtk_text_buffer_insert_at_cursor (buffer, license_agreement, strlen (license_agreement));
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "textview_details");
+	gtk_text_view_set_buffer (GTK_TEXT_VIEW (widget), buffer);
+
+	/* set minimum size a bit bigger */
+	gtk_widget_set_size_request (widget, 100, 200);
+
+	/* show window */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	gtk_widget_show (widget);
+
+	g_object_unref (buffer);
+
+	return TRUE;
+}
+
+/**
+ * gpk_eula_helper_set_parent:
+ **/
+gboolean
+gpk_eula_helper_set_parent (GpkEulaHelper *eula_helper, GtkWindow *window)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_EULA_HELPER (eula_helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	gtk_window_set_transient_for (GTK_WINDOW (widget), window);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (GTK_WINDOW (widget), "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_eula_helper_class_init:
+ * @klass: The GpkEulaHelperClass
+ **/
+static void
+gpk_eula_helper_class_init (GpkEulaHelperClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_eula_helper_finalize;
+	g_type_class_add_private (klass, sizeof (GpkEulaHelperPrivate));
+	signals [GPK_EULA_HELPER_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkEulaHelperClass, event),
+			      NULL, NULL, gpk_marshal_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+}
+
+/**
+ * gpk_eula_helper_init:
+ **/
+static void
+gpk_eula_helper_init (GpkEulaHelper *eula_helper)
+{
+	GtkWidget *widget;
+
+	eula_helper->priv = GPK_EULA_HELPER_GET_PRIVATE (eula_helper);
+
+	eula_helper->priv->eula_id = NULL;
+	eula_helper->priv->glade_xml = glade_xml_new (GPK_DATA "/gpk-eula.glade", NULL, NULL);
+
+	/* connect up default actions */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_eula_helper_button_cancel_cb), eula_helper);
+
+	/* set icon name */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+
+	/* connect up buttons */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "button_agree");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_eula_helper_button_agree_cb), eula_helper);
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "button_help");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_eula_helper_button_help_cb), eula_helper);
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "button_cancel");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_eula_helper_button_cancel_cb), eula_helper);
+}
+
+/**
+ * gpk_eula_helper_finalize:
+ **/
+static void
+gpk_eula_helper_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkEulaHelper *eula_helper;
+
+	g_return_if_fail (GPK_IS_EULA_HELPER (object));
+
+	eula_helper = GPK_EULA_HELPER (object);
+
+	/* hide window */
+	widget = glade_xml_get_widget (eula_helper->priv->glade_xml, "dialog_eula");
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_free (eula_helper->priv->eula_id);
+	g_object_unref (eula_helper->priv->glade_xml);
+
+	G_OBJECT_CLASS (gpk_eula_helper_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_eula_helper_new:
+ **/
+GpkEulaHelper *
+gpk_eula_helper_new (void)
+{
+	GpkEulaHelper *eula_helper;
+	eula_helper = g_object_new (GPK_TYPE_EULA_HELPER, NULL);
+	return GPK_EULA_HELPER (eula_helper);
+}
+

Added: trunk/src/gpk-eula-helper.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-eula-helper.h	Sun Mar 15 12:31:27 2009
@@ -0,0 +1,67 @@
+/* -*- 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_EULA_HELPER_H
+#define __GPK_EULA_HELPER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_EULA_HELPER		(gpk_eula_helper_get_type ())
+#define GPK_EULA_HELPER(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_EULA_HELPER, GpkEulaHelper))
+#define GPK_EULA_HELPER_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_EULA_HELPER, GpkEulaHelperClass))
+#define GPK_IS_EULA_HELPER(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_EULA_HELPER))
+#define GPK_IS_EULA_HELPER_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_EULA_HELPER))
+#define GPK_EULA_HELPER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_EULA_HELPER, GpkEulaHelperClass))
+#define GPK_EULA_HELPER_ERROR		(gpk_eula_helper_error_quark ())
+#define GPK_EULA_HELPER_TYPE_ERROR	(gpk_eula_helper_error_get_type ())
+
+typedef struct GpkEulaHelperPrivate GpkEulaHelperPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkEulaHelperPrivate	*priv;
+} GpkEulaHelper;
+
+typedef struct
+{
+	void		(* event)			(GpkEulaHelper		*eula_helper,
+							 GtkResponseType	 type,
+							 const gchar		*eula_id);
+	GObjectClass	parent_class;
+} GpkEulaHelperClass;
+
+GType		 gpk_eula_helper_get_type	  	(void);
+GpkEulaHelper	*gpk_eula_helper_new			(void);
+gboolean	 gpk_eula_helper_set_parent		(GpkEulaHelper		*eula_helper,
+							 GtkWindow		*window);
+gboolean	 gpk_eula_helper_show			(GpkEulaHelper		*eula_helper,
+							 const gchar		*eula_id,
+							 const gchar		*package_id,
+							 const gchar		*vendor_name,
+							 const gchar		*license_agreement);
+
+G_END_DECLS
+
+#endif /* __GPK_EULA_HELPER_H */

Modified: trunk/src/gpk-marshal.list
==============================================================================
--- trunk/src/gpk-marshal.list	(original)
+++ trunk/src/gpk-marshal.list	Sun Mar 15 12:31:27 2009
@@ -1,2 +1,3 @@
 VOID:UINT,STRING
+VOID:UINT,STRING,STRING
 

Added: trunk/src/gpk-repo-signature-helper.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-repo-signature-helper.c	Sun Mar 15 12:31:27 2009
@@ -0,0 +1,230 @@
+/* -*- 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 <glade/glade.h>
+
+#include "gpk-repo-signature-helper.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+
+#include "egg-debug.h"
+
+static void     gpk_repo_signature_helper_finalize	(GObject	  *object);
+
+#define GPK_REPO_SIGNATURE_HELPER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_REPO_SIGNATURE_HELPER, GpkRepoSignatureHelperPrivate))
+
+struct GpkRepoSignatureHelperPrivate
+{
+	GladeXML		*glade_xml;
+	gchar			*key_id;
+	gchar			*package_id;
+};
+
+enum {
+	GPK_REPO_SIGNATURE_HELPER_EVENT,
+	GPK_REPO_SIGNATURE_HELPER_LAST_SIGNAL
+};
+
+static guint signals [GPK_REPO_SIGNATURE_HELPER_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkRepoSignatureHelper, gpk_repo_signature_helper, G_TYPE_OBJECT)
+
+/**
+ * gpk_repo_signature_helper_button_yes_cb:
+ **/
+static void
+gpk_repo_signature_helper_button_yes_cb (GtkWidget *widget, GpkRepoSignatureHelper *repo_signature_helper)
+{
+	g_signal_emit (repo_signature_helper, signals [GPK_REPO_SIGNATURE_HELPER_EVENT], 0,
+		       GTK_RESPONSE_YES, repo_signature_helper->priv->key_id, repo_signature_helper->priv->package_id);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_repo_signature_helper_button_no_cb:
+ **/
+static void
+gpk_repo_signature_helper_button_no_cb (GtkWidget *widget, GpkRepoSignatureHelper *repo_signature_helper)
+{
+	g_signal_emit (repo_signature_helper, signals [GPK_REPO_SIGNATURE_HELPER_EVENT], 0,
+		       GTK_RESPONSE_NO, repo_signature_helper->priv->key_id, repo_signature_helper->priv->package_id);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_repo_signature_helper_button_help_cb:
+ **/
+static void
+gpk_repo_signature_helper_button_help_cb (GtkWidget *widget, GpkRepoSignatureHelper *repo_signature_helper)
+{
+	/* show the help */
+	gpk_gnome_help ("gpg-signature");
+}
+
+/**
+ * gpk_repo_signature_helper_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_repo_signature_helper_show (GpkRepoSignatureHelper *repo_signature_helper, 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)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_REPO_SIGNATURE_HELPER (repo_signature_helper), FALSE);
+	g_return_val_if_fail (package_id != NULL, FALSE);
+
+	/* cache */
+	g_free (repo_signature_helper->priv->key_id);
+	g_free (repo_signature_helper->priv->package_id);
+	repo_signature_helper->priv->key_id = g_strdup (key_id);
+	repo_signature_helper->priv->package_id = g_strdup (package_id);
+
+	/* show correct text */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "label_name");
+	gtk_label_set_label (GTK_LABEL (widget), repository_name);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "label_url");
+	gtk_label_set_label (GTK_LABEL (widget), key_url);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "label_user");
+	gtk_label_set_label (GTK_LABEL (widget), key_userid);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "label_id");
+	gtk_label_set_label (GTK_LABEL (widget), key_id);
+
+	/* show window */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	gtk_widget_show (widget);
+
+	return TRUE;
+}
+
+/**
+ * gpk_repo_signature_helper_set_parent:
+ **/
+gboolean
+gpk_repo_signature_helper_set_parent (GpkRepoSignatureHelper *repo_signature_helper, GtkWindow *window)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_REPO_SIGNATURE_HELPER (repo_signature_helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	gtk_window_set_transient_for (GTK_WINDOW (widget), window);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (GTK_WINDOW (widget), "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_repo_signature_helper_class_init:
+ * @klass: The GpkRepoSignatureHelperClass
+ **/
+static void
+gpk_repo_signature_helper_class_init (GpkRepoSignatureHelperClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_repo_signature_helper_finalize;
+	g_type_class_add_private (klass, sizeof (GpkRepoSignatureHelperPrivate));
+	signals [GPK_REPO_SIGNATURE_HELPER_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkRepoSignatureHelperClass, event),
+			      NULL, NULL, gpk_marshal_VOID__UINT_STRING_STRING,
+			      G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
+}
+
+/**
+ * gpk_repo_signature_helper_init:
+ **/
+static void
+gpk_repo_signature_helper_init (GpkRepoSignatureHelper *repo_signature_helper)
+{
+	GtkWidget *widget;
+
+	repo_signature_helper->priv = GPK_REPO_SIGNATURE_HELPER_GET_PRIVATE (repo_signature_helper);
+
+	repo_signature_helper->priv->key_id = NULL;
+	repo_signature_helper->priv->package_id = NULL;
+	repo_signature_helper->priv->glade_xml = glade_xml_new (GPK_DATA "/gpk-signature.glade", NULL, NULL);
+
+	/* connect up default actions */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_repo_signature_helper_button_no_cb), repo_signature_helper);
+
+	/* set icon name */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+
+	/* connect up buttons */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "button_yes");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_repo_signature_helper_button_yes_cb), repo_signature_helper);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "button_help");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_repo_signature_helper_button_help_cb), repo_signature_helper);
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "button_no");
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_repo_signature_helper_button_no_cb), repo_signature_helper);
+}
+
+/**
+ * gpk_repo_signature_helper_finalize:
+ **/
+static void
+gpk_repo_signature_helper_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkRepoSignatureHelper *repo_signature_helper;
+
+	g_return_if_fail (GPK_IS_REPO_SIGNATURE_HELPER (object));
+
+	repo_signature_helper = GPK_REPO_SIGNATURE_HELPER (object);
+
+	/* hide window */
+	widget = glade_xml_get_widget (repo_signature_helper->priv->glade_xml, "dialog_gpg");
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_free (repo_signature_helper->priv->key_id);
+	g_free (repo_signature_helper->priv->package_id);
+	g_object_unref (repo_signature_helper->priv->glade_xml);
+
+	G_OBJECT_CLASS (gpk_repo_signature_helper_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_repo_signature_helper_new:
+ **/
+GpkRepoSignatureHelper *
+gpk_repo_signature_helper_new (void)
+{
+	GpkRepoSignatureHelper *repo_signature_helper;
+	repo_signature_helper = g_object_new (GPK_TYPE_REPO_SIGNATURE_HELPER, NULL);
+	return GPK_REPO_SIGNATURE_HELPER (repo_signature_helper);
+}
+

Added: trunk/src/gpk-repo-signature-helper.h
==============================================================================
--- (empty file)
+++ trunk/src/gpk-repo-signature-helper.h	Sun Mar 15 12:31:27 2009
@@ -0,0 +1,71 @@
+/* -*- 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_REPO_SIGNATURE_HELPER_H
+#define __GPK_REPO_SIGNATURE_HELPER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_REPO_SIGNATURE_HELPER		(gpk_repo_signature_helper_get_type ())
+#define GPK_REPO_SIGNATURE_HELPER(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_REPO_SIGNATURE_HELPER, GpkRepoSignatureHelper))
+#define GPK_REPO_SIGNATURE_HELPER_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_REPO_SIGNATURE_HELPER, GpkRepoSignatureHelperClass))
+#define GPK_IS_REPO_SIGNATURE_HELPER(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_REPO_SIGNATURE_HELPER))
+#define GPK_IS_REPO_SIGNATURE_HELPER_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_REPO_SIGNATURE_HELPER))
+#define GPK_REPO_SIGNATURE_HELPER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_REPO_SIGNATURE_HELPER, GpkRepoSignatureHelperClass))
+#define GPK_REPO_SIGNATURE_HELPER_ERROR		(gpk_repo_signature_helper_error_quark ())
+#define GPK_REPO_SIGNATURE_HELPER_TYPE_ERROR	(gpk_repo_signature_helper_error_get_type ())
+
+typedef struct GpkRepoSignatureHelperPrivate GpkRepoSignatureHelperPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkRepoSignatureHelperPrivate	*priv;
+} GpkRepoSignatureHelper;
+
+typedef struct
+{
+	void		(* event)				(GpkRepoSignatureHelper	*repo_signature_helper,
+								 GtkResponseType	 type,
+								 const gchar		*key_id,
+								 const gchar		*package_id);
+	GObjectClass	parent_class;
+} GpkRepoSignatureHelperClass;
+
+GType			 gpk_repo_signature_helper_get_type	(void);
+GpkRepoSignatureHelper	*gpk_repo_signature_helper_new		(void);
+gboolean		 gpk_repo_signature_helper_set_parent	(GpkRepoSignatureHelper	*repo_signature_helper,
+								 GtkWindow		*window);
+gboolean		 gpk_repo_signature_helper_show		(GpkRepoSignatureHelper	*repo_signature_helper,
+								 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);
+
+G_END_DECLS
+
+#endif /* __GPK_REPO_SIGNATURE_HELPER_H */

Modified: trunk/src/gpk-repo.c
==============================================================================
--- trunk/src/gpk-repo.c	(original)
+++ trunk/src/gpk-repo.c	Sun Mar 15 12:31:27 2009
@@ -467,6 +467,10 @@
 	if (!ret)
 		return 1;
 
+        /* 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");
+
 	/* are we already activated? */
 	egg_unique = egg_unique_new ();
 	ret = egg_unique_assign (egg_unique, "org.freedesktop.PackageKit.Repo");

Added: trunk/src/gpk-update-viewer2.c
==============================================================================
--- (empty file)
+++ trunk/src/gpk-update-viewer2.c	Sun Mar 15 12:31:27 2009
@@ -0,0 +1,2207 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-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.h>
+#include <glib/gi18n.h>
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <dbus/dbus-glib.h>
+
+#include <gconf/gconf-client.h>
+#include <packagekit-glib/packagekit.h>
+#include <libnotify/notify.h>
+
+#include "egg-debug.h"
+#include "egg-string.h"
+#include "egg-unique.h"
+#include "egg-markdown.h"
+
+#include "gpk-common.h"
+#include "gpk-gnome.h"
+#include "gpk-error.h"
+#include "gpk-consolekit.h"
+#include "gpk-cell-renderer-size.h"
+#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-repo-signature-helper.h"
+#include "gpk-eula-helper.h"
+
+static GMainLoop *loop = NULL;
+static GladeXML *glade_xml = NULL;
+static GtkListStore *list_store_updates = NULL;
+static GtkListStore *list_store_details = NULL;
+static GtkTextBuffer *text_buffer = NULL;
+static PkClient *client_primary = NULL;
+static PkClient *client_secondary = NULL;
+static PkControl *control = NULL;
+static PkPackageList *update_list = NULL;
+static GpkRepoSignatureHelper *repo_signature_helper = NULL;
+static GpkEulaHelper *eula_helper = NULL;
+static EggMarkdown *markdown = NULL;
+static PkPackageId *package_id_last = NULL;
+
+enum {
+	GPK_DESC_COLUMN_TITLE,
+	GPK_DESC_COLUMN_TEXT,
+	GPK_DESC_COLUMN_LAST
+};
+
+enum {
+	GPK_UPDATES_COLUMN_TEXT,
+	GPK_UPDATES_COLUMN_ID,
+	GPK_UPDATES_COLUMN_INFO,
+	GPK_UPDATES_COLUMN_SELECT,
+	GPK_UPDATES_COLUMN_SENSITIVE,
+	GPK_UPDATES_COLUMN_CLICKABLE,
+	GPK_UPDATES_COLUMN_RESTART,
+	GPK_UPDATES_COLUMN_SIZE,
+	GPK_UPDATES_COLUMN_PERCENTAGE,
+	GPK_UPDATES_COLUMN_STATUS,
+	GPK_UPDATES_COLUMN_DETAILS_OBJ,
+	GPK_UPDATES_COLUMN_UPDATE_DETAIL_OBJ,
+	GPK_UPDATES_COLUMN_LAST
+};
+
+static gboolean gpk_update_viewer_get_new_update_list (void);
+
+/**
+ * gpk_update_viewer_button_help_cb:
+ **/
+static void
+gpk_update_viewer_button_help_cb (GtkWidget *widget, gpointer data)
+{
+	const gchar *id = data;
+	gpk_gnome_help (id);
+}
+
+/**
+ * gpk_update_viewer_button_close_cb:
+ **/
+static void
+gpk_update_viewer_button_close_cb (GtkWidget *widget, gpointer data)
+{
+	g_main_loop_quit (loop);
+}
+
+/**
+ * gpk_update_viewer_undisable_packages:
+ **/
+static void
+gpk_update_viewer_undisable_packages ()
+{
+	GtkWidget *widget;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	/* set all the checkboxes sensitive */
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid) {
+		gtk_list_store_set (list_store_updates, &iter,
+				    GPK_UPDATES_COLUMN_SENSITIVE, TRUE, -1);
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+}
+
+/**
+ * gpk_update_viewer_button_install_cb:
+ **/
+static void
+gpk_update_viewer_button_install_cb (GtkWidget *widget, gpointer data)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean ret;
+	gboolean valid;
+	gboolean update;
+	gboolean selected_all = TRUE;
+	gboolean selected_any = FALSE;
+	gchar *package_id;
+	GError *error = NULL;
+	GPtrArray *array;
+	gchar **package_ids = NULL;
+
+	egg_debug ("Doing the package updates");
+	array = g_ptr_array_new ();
+
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	/* get the first iter in the list */
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	/* find out how many we should update */
+	while (valid) {
+		gtk_tree_model_get (model, &iter, GPK_UPDATES_COLUMN_SELECT, &update,
+				    GPK_UPDATES_COLUMN_ID, &package_id, -1);
+
+		/* set all the checkboxes insensitive */
+		gtk_list_store_set (list_store_updates, &iter,
+				    GPK_UPDATES_COLUMN_SENSITIVE, FALSE, -1);
+
+		/* ay selected? */
+		if (!update)
+			selected_all = FALSE;
+		else
+			selected_any = TRUE;
+
+		/* do something with the data */
+		if (update) {
+			g_ptr_array_add (array, package_id);
+		} else {
+			/* need to free the one in the array later */
+			g_free (package_id);
+		}
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	/* we have no checkboxes selected */
+	if (!selected_any) {
+		widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+		gpk_error_dialog_modal (GTK_WINDOW (widget),
+					/* TRANSLATORS: we clicked apply, but had no packages selected */
+					_("No updates selected"),
+					_("No updates are selected"), NULL);
+		return;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* set correct view */
+	package_ids = pk_package_ids_from_array (array);
+	ret = pk_client_update_packages (client_primary, package_ids, &error);
+	if (!ret) {
+		egg_warning ("cannot update packages: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
+
+	/* get rid of the array, and free the contents */
+	g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+	g_ptr_array_free (array, TRUE);
+}
+
+/**
+ * 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
+gpk_update_viewer_button_upgrade_cb (GtkWidget *widget, gpointer data)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	ret = g_spawn_command_line_async ("/usr/share/PackageKit/pk-upgrade-distro.sh", NULL);
+	if (!ret) {
+		egg_warning ("Failure launching pk-upgrade-distro.sh: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+/**
+ * gpk_update_viewer_button_delete_event_cb:
+ **/
+static gboolean
+gpk_update_viewer_button_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+	g_main_loop_quit (loop);
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_find_iter_model_cb:
+ **/
+static gboolean
+gpk_update_viewer_find_iter_model_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, const PkPackageId *id)
+{
+	gchar *id_tmp = NULL;
+	GtkTreePath **_path = NULL;
+	PkPackageId *id_new;
+	gboolean ret = FALSE;
+
+	_path = (GtkTreePath **) g_object_get_data (G_OBJECT(model), "_path");
+	gtk_tree_model_get (model, iter, GPK_UPDATES_COLUMN_ID, &id_tmp, -1);
+
+	/* only match on the name */
+	id_new = pk_package_id_new_from_string (id_tmp);
+	if (g_strcmp0 (id_new->name, id->name) == 0) {
+		*_path = gtk_tree_path_copy (path);
+		ret = TRUE;
+	}
+	pk_package_id_free (id_new);
+	return ret;
+}
+
+/**
+ * gpk_update_viewer_model_get_path:
+ **/
+static GtkTreePath *
+gpk_update_viewer_model_get_path (GtkTreeModel *model, const PkPackageId *id)
+{
+	GtkTreePath *path = NULL;
+	g_object_set_data (G_OBJECT(model), "_path", (gpointer) &path);
+	gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) gpk_update_viewer_find_iter_model_cb, (gpointer) id);
+	g_object_steal_data (G_OBJECT(model), "_path");
+	return path;
+}
+
+/**
+ * gpk_update_viewer_details_cb:
+ **/
+static void
+gpk_update_viewer_details_cb (PkClient *client, const PkDetailsObj *obj, gpointer data)
+{
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	treeview = GTK_TREE_VIEW (glade_xml_get_widget (glade_xml, "treeview_updates"));
+	model = gtk_tree_view_get_model (treeview);
+
+	path = gpk_update_viewer_model_get_path (model, obj->id);
+	if (path == NULL) {
+		egg_debug ("not found ID for group");
+		return;
+	}
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	gtk_list_store_set (list_store_updates, &iter,
+			    GPK_UPDATES_COLUMN_DETAILS_OBJ, (gpointer) pk_details_obj_copy (obj),
+			    GPK_UPDATES_COLUMN_SIZE, (gint)obj->size, -1);
+	/* in cache */
+	if (obj->size == 0)
+		gtk_list_store_set (list_store_updates, &iter,
+				    GPK_UPDATES_COLUMN_STATUS, PK_INFO_ENUM_DOWNLOADING, -1);
+}
+
+/**
+ * gpk_update_viewer_is_update_info:
+ **/
+static gboolean
+gpk_update_viewer_is_update_info (PkInfoEnum info)
+{
+	if (info == PK_INFO_ENUM_LOW)
+		return TRUE;
+	if (info == PK_INFO_ENUM_NORMAL)
+		return TRUE;
+	if (info == PK_INFO_ENUM_IMPORTANT)
+		return TRUE;
+	if (info == PK_INFO_ENUM_SECURITY)
+		return TRUE;
+	if (info == PK_INFO_ENUM_BUGFIX)
+		return TRUE;
+	if (info == PK_INFO_ENUM_ENHANCEMENT)
+		return TRUE;
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_package_cb:
+ **/
+static void
+gpk_update_viewer_package_cb (PkClient *client, const PkPackageObj *obj, gpointer data)
+{
+	PkRoleEnum role;
+	gchar *text = NULL;
+	gchar *package_id;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkWidget *widget;
+	GtkTreePath *path;
+	gboolean selected;
+
+	pk_client_get_role (client, &role, NULL, NULL);
+	egg_debug ("role = %s, package = %s:%s:%s", pk_role_enum_to_text (role),
+		  pk_info_enum_to_text (obj->info), obj->id->name, obj->summary);
+
+	/* convert to string */
+	package_id = pk_package_id_to_string (obj->id);
+
+	/* used for progress */
+	if (!gpk_update_viewer_is_update_info (obj->info)) {
+		pk_package_id_free (package_id_last);
+		package_id_last = pk_package_id_copy (obj->id);
+
+		/* find model */
+		widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+		model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+		/* update icon */
+		path = gpk_update_viewer_model_get_path (model, obj->id);
+		if (path == NULL) {
+			egg_debug ("not found ID for package");
+			goto out;
+		}
+
+		gtk_tree_model_get_iter (model, &iter, path);
+		gtk_list_store_set (list_store_updates, &iter,
+				    GPK_UPDATES_COLUMN_STATUS, obj->info, -1);
+		gtk_tree_path_free (path);
+		goto out;
+	}
+
+	/* add to list store */
+	text = gpk_package_id_format_twoline (obj->id, obj->summary);
+	selected = (obj->info != PK_INFO_ENUM_BLOCKED);
+	gtk_list_store_append (list_store_updates, &iter);
+	gtk_list_store_set (list_store_updates, &iter,
+			    GPK_UPDATES_COLUMN_TEXT, text,
+			    GPK_UPDATES_COLUMN_ID, package_id,
+			    GPK_UPDATES_COLUMN_INFO, obj->info,
+			    GPK_UPDATES_COLUMN_SELECT, selected,
+			    GPK_UPDATES_COLUMN_SENSITIVE, selected,
+			    GPK_UPDATES_COLUMN_CLICKABLE, selected,
+			    GPK_UPDATES_COLUMN_RESTART, PK_RESTART_ENUM_NONE,
+			    GPK_UPDATES_COLUMN_STATUS, PK_INFO_ENUM_UNKNOWN,
+			    GPK_UPDATES_COLUMN_SIZE, 0,
+			    GPK_UPDATES_COLUMN_PERCENTAGE, 0,
+			    -1);
+out:
+	g_free (package_id);
+	g_free (text);
+}
+
+/**
+ * gpk_update_viewer_update_detail_cb:
+ **/
+static void
+gpk_update_viewer_update_detail_cb (PkClient *client, const PkUpdateDetailObj *obj, gpointer data)
+{
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	treeview = GTK_TREE_VIEW (glade_xml_get_widget (glade_xml, "treeview_updates"));
+	model = gtk_tree_view_get_model (treeview);
+
+	path = gpk_update_viewer_model_get_path (model, obj->id);
+	if (path == NULL) {
+		egg_warning ("not found ID for update detail");
+		return;
+	}
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	gtk_list_store_set (list_store_updates, &iter,
+			    GPK_UPDATES_COLUMN_UPDATE_DETAIL_OBJ, (gpointer) pk_update_detail_obj_copy (obj),
+			    GPK_UPDATES_COLUMN_RESTART, obj->restart, -1);
+}
+
+/**
+ * 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 = glade_xml_get_widget (glade_xml, "button_install");
+		gtk_widget_show (widget);
+		widget = glade_xml_get_widget (glade_xml, "button_cancel");
+		gtk_widget_hide (widget);
+	} else {
+		widget = glade_xml_get_widget (glade_xml, "button_install");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "button_cancel");
+		gtk_widget_show (widget);
+	}
+}
+
+/**
+ * gpk_update_viewer_reconsider_info:
+ **/
+static void
+gpk_update_viewer_reconsider_info (GtkTreeModel *model)
+{
+	GtkTreeIter iter;
+	GtkWidget *widget;
+	GtkWidget *main_window;
+	gboolean valid;
+	gboolean selected;
+	gboolean any_selected = FALSE;
+	guint len;
+	guint size;
+	guint size_total = 0;
+	guint number_total = 0;
+	PkRestartEnum restart;
+	PkRestartEnum restart_worst = PK_RESTART_ENUM_NONE;
+	gchar *text;
+	gchar *text_size;
+
+	/* if there are no entries selected, deselect the button */
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid) {
+		gtk_tree_model_get (model, &iter,
+				    GPK_UPDATES_COLUMN_SELECT, &selected,
+				    GPK_UPDATES_COLUMN_RESTART, &restart,
+				    GPK_UPDATES_COLUMN_SIZE, &size,
+				    -1);
+		if (selected) {
+			any_selected = TRUE;
+			size_total += size;
+			number_total++;
+			if (restart > restart_worst)
+				restart_worst = restart;
+		}
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	/* action button */
+	widget = glade_xml_get_widget (glade_xml, "button_install");
+	gtk_widget_set_sensitive (widget, any_selected);
+	main_window = glade_xml_get_widget (glade_xml, "dialog_updates");
+
+	/* have we got any updates */
+	len = PK_OBJ_LIST(update_list)->len;
+	if (len == 0) {
+		widget = glade_xml_get_widget (glade_xml, "vpaned_updates");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+		gtk_window_set_resizable (GTK_WINDOW(widget), FALSE);
+
+		/* set state */
+		widget = glade_xml_get_widget (glade_xml, "image_progress");
+		gtk_image_set_from_icon_name (GTK_IMAGE (widget), "dialog-information", GTK_ICON_SIZE_DIALOG);
+		gtk_widget_show (widget);
+
+		widget = glade_xml_get_widget (glade_xml, "label_summary");
+		/* TRANSLATORS: there are no updates */
+		text = g_strdup_printf ("<b>%s</b>", _("There are no updates available for your computer"));
+		gtk_label_set_label (GTK_LABEL (widget), text);
+		g_free (text);
+		gtk_widget_show (widget);
+
+		/* close button */
+		widget = glade_xml_get_widget (glade_xml, "button_close");
+		gtk_widget_show (widget);
+		gtk_window_set_focus (GTK_WINDOW(main_window), widget);
+
+		/* header */
+		widget = glade_xml_get_widget (glade_xml, "hbox_header");
+		gtk_widget_hide (widget);
+
+		widget = glade_xml_get_widget (glade_xml, "button_help");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "button_install");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "label_status");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "label_package");
+		gtk_widget_hide (widget);
+		goto out;
+	}
+
+	/* details */
+	widget = glade_xml_get_widget (glade_xml, "vpaned_updates");
+	gtk_widget_show (widget);
+	widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+	gtk_window_set_resizable (GTK_WINDOW(widget), TRUE);
+	widget = glade_xml_get_widget (glade_xml, "button_install");
+	gtk_widget_show (widget);
+	widget = glade_xml_get_widget (glade_xml, "button_help");
+	gtk_widget_show (widget);
+	gtk_window_set_focus (GTK_WINDOW(main_window), widget);
+	widget = glade_xml_get_widget (glade_xml, "button_close");
+	gtk_widget_hide (widget);
+
+	/* restart */
+	widget = glade_xml_get_widget (glade_xml, "label_package");
+	if (restart_worst == PK_RESTART_ENUM_NONE) {
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "image_progress");
+		gtk_widget_hide (widget);
+		widget = glade_xml_get_widget (glade_xml, "label_summary");
+		gtk_label_set_label (GTK_LABEL (widget), "");
+	} else {
+		gtk_label_set_label (GTK_LABEL (widget), gpk_restart_enum_to_localised_text_future (restart_worst));
+		gtk_widget_show (widget);
+		widget = glade_xml_get_widget (glade_xml, "image_progress");
+		gtk_image_set_from_icon_name (GTK_IMAGE (widget), gpk_restart_enum_to_icon_name (restart_worst), GTK_ICON_SIZE_BUTTON);
+		gtk_widget_show (widget);
+	}
+
+	/* header */
+	widget = glade_xml_get_widget (glade_xml, "label_header_title");
+	text = g_strdup_printf (ngettext ("There is %i update available",
+					  "There are %i updates available", len), len);
+	text_size = g_strdup_printf ("<big><b>%s</b></big>", text);
+	gtk_label_set_label (GTK_LABEL (widget), text_size);
+	g_free (text);
+	g_free (text_size);
+	widget = glade_xml_get_widget (glade_xml, "hbox_header");
+	gtk_widget_show (widget);
+
+	/* total */
+	widget = glade_xml_get_widget (glade_xml, "label_summary");
+	if (number_total == 0) {
+		gtk_label_set_label (GTK_LABEL (widget), "");
+	} else {
+		text_size = g_format_size_for_display (size_total);
+		/* TRANSLATORS: how many updates are selected in the UI */
+		text = g_strdup_printf (ngettext ("%i update selected (%s)",
+						  "%i updates selected (%s)",
+						  number_total), number_total, text_size);
+		gtk_label_set_label (GTK_LABEL (widget), text);
+		g_free (text);
+		g_free (text_size);
+	}
+
+	widget = glade_xml_get_widget (glade_xml, "label_summary");
+	gtk_widget_show (widget);
+out:
+	return;
+}
+
+/**
+ * gpk_update_viewer_status_changed_cb:
+ **/
+static void
+gpk_update_viewer_status_changed_cb (PkClient *client, PkStatusEnum status, gpointer data)
+{
+	GtkWidget *widget;
+	const gchar *text;
+
+	egg_debug ("status %s", pk_status_enum_to_text (status));
+
+	/* clear package */
+	if (status == PK_STATUS_ENUM_WAIT) {
+		widget = glade_xml_get_widget (glade_xml, "label_package");
+		gtk_label_set_label (GTK_LABEL (widget), "");
+	}
+
+	/* set status */
+	widget = glade_xml_get_widget (glade_xml, "label_status");
+	if (status == PK_STATUS_ENUM_FINISHED) {
+		gtk_label_set_label (GTK_LABEL (widget), "");
+		widget = glade_xml_get_widget (glade_xml, "image_progress");
+		gtk_widget_hide (widget);
+		goto out;
+	}
+	if (status == PK_STATUS_ENUM_QUERY)
+		text = _("Getting list of updates");
+	else
+		text = gpk_status_enum_to_localised_text (status);
+
+	/* set label */
+	gtk_label_set_label (GTK_LABEL (widget), text);
+	widget = glade_xml_get_widget (glade_xml, "image_progress");
+
+	/* set icon */
+	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);
+}
+
+/**
+ * gpk_update_viewer_treeview_update_toggled:
+ **/
+static void
+gpk_update_viewer_treeview_update_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
+{
+	GtkTreeModel *model = (GtkTreeModel *) data;
+	GtkTreeIter iter;
+	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+	gboolean update;
+	gchar *package_id;
+
+	/* get toggled iter */
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter, GPK_UPDATES_COLUMN_SELECT, &update,
+			    GPK_UPDATES_COLUMN_ID, &package_id, -1);
+
+	/* unstage */
+	update ^= 1;
+
+	egg_debug ("update %s[%i]", package_id, update);
+	g_free (package_id);
+
+	/* set new value */
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter, GPK_UPDATES_COLUMN_SELECT, update, -1);
+
+	/* clean up */
+	gtk_tree_path_free (path);
+
+	/* if there are no entries selected, deselect the button */
+	gpk_update_viewer_reconsider_info (model);
+}
+
+/**
+ * gpk_update_viewer_treeview_details_size_allocate_cb:
+ **/
+static void
+gpk_update_viewer_treeview_details_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
+{
+	GtkTreeViewColumn *column;
+	gint width;
+
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
+	width = gtk_tree_view_column_get_width (column);
+	g_object_set (cell, "wrap-width", allocation->width - width - 10, NULL);
+}
+
+/**
+ * gpk_update_viewer_treeview_updates_size_allocate_cb:
+ **/
+static void
+gpk_update_viewer_treeview_updates_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
+{
+	GtkTreeViewColumn *column;
+	gint width;
+
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
+	width = gtk_tree_view_column_get_width (column);
+	g_object_set (cell, "wrap-width", allocation->width - width - 200, NULL);
+}
+
+/**
+ * gpk_update_viewer_treeview_add_columns_details:
+ **/
+static void
+gpk_update_viewer_treeview_add_columns_details (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* title */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "yalign", 0.0, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer, "markup", GPK_DESC_COLUMN_TITLE);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "yalign", 0.0, NULL);
+	g_object_set (renderer, "wrap-mode", PANGO_WRAP_WORD, NULL);
+	g_signal_connect (treeview, "size-allocate", G_CALLBACK (gpk_update_viewer_treeview_details_size_allocate_cb), renderer);
+	/* TRANSLATORS: The information about the update, not currently shown */
+	column = gtk_tree_view_column_new_with_attributes (_("Text"), renderer,
+							   "markup", GPK_DESC_COLUMN_TEXT, NULL);
+	gtk_tree_view_append_column (treeview, column);
+}
+
+/**
+ * gpk_update_viewer_treeview_add_columns_update:
+ **/
+static void
+gpk_update_viewer_treeview_add_columns_update (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeModel *model;
+
+	/* restart */
+	renderer = gpk_cell_renderer_restart_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	column = gtk_tree_view_column_new_with_attributes ("", renderer,
+							   "value", GPK_UPDATES_COLUMN_RESTART, NULL);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), FALSE);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* --- column for image and toggle --- */
+	column = gtk_tree_view_column_new ();
+	/* TRANSLATORS: if the update should be installed */
+	gtk_tree_view_column_set_title (column, _("Install"));
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), FALSE);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_UPDATES_COLUMN_INFO);
+
+	/* info */
+	renderer = gpk_cell_renderer_info_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute (column, renderer, "value", GPK_UPDATES_COLUMN_INFO);
+
+	/* select toggle */
+	renderer = gtk_cell_renderer_toggle_new ();
+	model = gtk_tree_view_get_model (treeview);
+	g_signal_connect (renderer, "toggled", G_CALLBACK (gpk_update_viewer_treeview_update_toggled), model);
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute (column, renderer, "active", GPK_UPDATES_COLUMN_SELECT);
+	gtk_tree_view_column_add_attribute (column, renderer, "activatable", GPK_UPDATES_COLUMN_CLICKABLE);
+	gtk_tree_view_column_add_attribute (column, renderer, "sensitive", GPK_UPDATES_COLUMN_SENSITIVE);
+
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "yalign", 0.0, NULL);
+	g_object_set (renderer, "wrap-mode", PANGO_WRAP_WORD, NULL);
+	/* TRANSLATORS: a column that has name of the package that will be updated */
+	column = gtk_tree_view_column_new_with_attributes (_("Software"), renderer,
+							   "markup", GPK_UPDATES_COLUMN_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_UPDATES_COLUMN_TEXT);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
+	gtk_tree_view_append_column (treeview, column);
+	g_signal_connect (treeview, "size-allocate", G_CALLBACK (gpk_update_viewer_treeview_updates_size_allocate_cb), renderer);
+
+	/* column for size */
+	renderer = gpk_cell_renderer_size_new ();
+	/* TRANSLATORS: a column that has size of the package */
+	column = gtk_tree_view_column_new_with_attributes (_("Size"), renderer,
+							   "value", GPK_UPDATES_COLUMN_SIZE, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_UPDATES_COLUMN_SIZE);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), FALSE);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* --- column for progress --- */
+	column = gtk_tree_view_column_new ();
+	/* TRANSLATORS: a column that has state of each package */
+	gtk_tree_view_column_set_title (column, _("Status"));
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), FALSE);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_UPDATES_COLUMN_STATUS);
+
+	/* info */
+	renderer = gpk_cell_renderer_info_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer, "value", GPK_UPDATES_COLUMN_STATUS);
+
+	/* column for progress */
+	renderer = gpk_cell_renderer_percentage_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer, "percent", GPK_UPDATES_COLUMN_PERCENTAGE);
+	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), FALSE);
+
+	gtk_tree_view_append_column (treeview, column);
+}
+
+/**
+ * gpk_update_viewer_add_description_item:
+ **/
+static void
+gpk_update_viewer_add_description_item (const gchar *title, const gchar *text)
+{
+	gchar *markup;
+	GtkWidget *tree_view;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+
+	/* format */
+	markup = g_strdup_printf ("<b>%s:</b>", title);
+
+	egg_debug ("%s: %s", markup, text);
+	gtk_list_store_append (list_store_details, &iter);
+	gtk_list_store_set (list_store_details, &iter,
+			    GPK_DESC_COLUMN_TITLE, markup,
+			    GPK_DESC_COLUMN_TEXT, text,
+			    -1);
+
+	g_free (markup);
+
+	tree_view = glade_xml_get_widget (glade_xml, "treeview_details");
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (tree_view));
+}
+
+/**
+ * gpk_text_buffer_insert_link:
+ **/
+static void
+gpk_text_buffer_insert_link (GtkTextBuffer *buffer, GtkTextIter *iter, const gchar *text, const gchar *href)
+{
+	GtkTextTag *tag;
+	tag = gtk_text_buffer_create_tag (buffer, NULL,
+					  "foreground", "blue",
+					  "underline", PANGO_UNDERLINE_SINGLE,
+					  NULL);
+	g_object_set_data (G_OBJECT (tag), "href", g_strdup (href));
+	gtk_text_buffer_insert_with_tags (buffer, iter, text, -1, tag, NULL);
+}
+
+/**
+ * gpk_update_viewer_add_description_link_item:
+ **/
+static void
+gpk_update_viewer_add_description_link_item (const gchar *title, const gchar *url_string)
+{
+	const gchar *text;
+	const gchar *uri;
+	gchar **urls;
+	guint length;
+	gint i;
+	GtkTextIter start;
+	GtkTextIter iter;
+
+	urls = g_strsplit (url_string, ";", 0);
+	length = g_strv_length (urls);
+
+	/* could we have malformed descriptions with ';' in them? */
+	if (length % 2 != 0) {
+		egg_warning ("length not correct, correcting");
+		length--;
+	}
+
+	/* insert at end */
+	gtk_text_buffer_get_bounds (text_buffer, &start, &iter);
+	gtk_text_buffer_insert (text_buffer, &iter, "\n\n", -1);
+	gtk_text_buffer_insert (text_buffer, &iter, title, -1);
+
+	for (i=0; i<length; i+=2) {
+		uri = urls[i];
+		text = urls[i+1];
+		if (egg_strzero (text))
+			text = uri;
+
+		gtk_text_buffer_insert (text_buffer, &iter, "\nâ ", -1);
+		gpk_text_buffer_insert_link (text_buffer, &iter, text, uri);
+	}
+	g_strfreev (urls);
+}
+
+/**
+ * gpk_update_viewer_get_pretty_from_composite:
+ **/
+static gchar *
+gpk_update_viewer_get_pretty_from_composite (const gchar *package_ids_delimit)
+{
+	guint i;
+	guint length;
+	gchar **package_ids;
+	gchar *pretty = NULL;
+	GString *string;
+	PkPackageId *id;
+
+	/* do we have any data? */
+	if (egg_strzero (package_ids_delimit))
+		goto out;
+
+	string = g_string_new ("");
+	package_ids = pk_package_ids_from_text (package_ids_delimit);
+	length = g_strv_length (package_ids);
+	for (i=0; i<length; i++) {
+		id = pk_package_id_new_from_string (package_ids[i]);
+		pretty = gpk_package_id_name_version (id);
+		pk_package_id_free (id);
+		g_string_append (string, pretty);
+		g_string_append_c (string, '\n');
+		g_free (pretty);
+	}
+
+	/* remove trailing \n */
+	g_string_set_size (string, string->len - 1);
+	pretty = g_string_free (string, FALSE);
+	g_strfreev (package_ids);
+out:
+	return pretty;
+}
+
+/**
+ * gpk_update_viewer_populate_details:
+ **/
+static void
+gpk_update_viewer_populate_details (const PkUpdateDetailObj *obj)
+{
+
+	GtkWidget *widget;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreeIter treeiter;
+	gchar *package_pretty;
+	const gchar *info_text;
+	PkInfoEnum info;
+	gchar *line;
+
+	/* clear existing list */
+	gtk_list_store_clear (list_store_details);
+
+	/* get info  */
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	if (gtk_tree_selection_get_selected (selection, &model, &treeiter))
+		gtk_tree_model_get (model, &treeiter,
+				    GPK_UPDATES_COLUMN_INFO, &info, -1);
+	else
+		info = PK_INFO_ENUM_NORMAL;
+
+	info_text = gpk_info_enum_to_localised_text (info);
+	/* TRANSLATORS: this is the update type, e.g. security */
+	gpk_update_viewer_add_description_item (_("Type"), info_text);
+
+	/* state */
+	if (obj->state != PK_UPDATE_STATE_ENUM_UNKNOWN) {
+		info_text = gpk_update_state_enum_to_localised_text (obj->state);
+		/* TRANSLATORS: this is the stability status of the update */
+		gpk_update_viewer_add_description_item (_("State"), info_text);
+	}
+
+	/* issued */
+	if (obj->issued != NULL) {
+		line = pk_iso8601_from_date (obj->issued);
+		/* TRANSLATORS: this is when the update was issued */
+		gpk_update_viewer_add_description_item (_("Issued"), line);
+		g_free (line);
+	}
+
+	/* updated */
+	if (obj->updated != NULL) {
+		line = pk_iso8601_from_date (obj->updated);
+		/* TRANSLATORS: this is when (if?) the update was updated */
+		gpk_update_viewer_add_description_item (_("Updated"), line);
+		g_free (line);
+	}
+
+	package_pretty = gpk_package_id_name_version (obj->id);
+	/* TRANSLATORS: this is the package version */
+	gpk_update_viewer_add_description_item (_("New version"), package_pretty);
+	g_free (package_pretty);
+
+	/* split and add */
+	package_pretty = gpk_update_viewer_get_pretty_from_composite (obj->updates);
+	if (!egg_strzero (package_pretty)) {
+		/* TRANSLATORS: this is a list of packages that are updated */
+		gpk_update_viewer_add_description_item (_("Installed version"), package_pretty);
+	}
+	g_free (package_pretty);
+
+	/* split and add */
+	package_pretty = gpk_update_viewer_get_pretty_from_composite (obj->obsoletes);
+	if (!egg_strzero (package_pretty)) {
+		/* TRANSLATORS: this is a list of packages that are obsoleted */
+		gpk_update_viewer_add_description_item (_("Obsoletes"), package_pretty);
+	}
+	g_free (package_pretty);
+
+	/* TRANSLATORS: this is the repository the package has come from */
+	gpk_update_viewer_add_description_item (_("Repository"), obj->id->data);
+
+	/* update text */
+	if (!egg_strzero (obj->update_text)) {
+		/* convert the bullets */
+		line = egg_markdown_parse (markdown, obj->update_text);
+		if (!egg_strzero (line))
+			gtk_text_buffer_set_markup (text_buffer, line);
+		g_free (line);
+	} else {
+		gtk_text_buffer_set_text (text_buffer, _("No update information"), -1);
+	}
+
+	/* changelog */
+	if (!egg_strzero (obj->changelog)) {
+		/* TRANSLATORS: this is a list of CVE (security) URLs */
+		gpk_update_viewer_add_description_item (_("Changes"), obj->changelog);
+	}
+
+	/* add all the links */
+	if (!egg_strzero (obj->vendor_url)) {
+		/* TRANSLATORS: this is a list of vendor URLs */
+		gpk_update_viewer_add_description_link_item (_("For more information about this update please visit:"), obj->vendor_url);
+	}
+	if (!egg_strzero (obj->bugzilla_url)) {
+		/* TRANSLATORS: this is a list of bugzilla URLs */
+		gpk_update_viewer_add_description_link_item (_("For more information about bugs fixed by this this update please visit:"), obj->bugzilla_url);
+	}
+	if (!egg_strzero (obj->cve_url)) {
+		/* TRANSLATORS: this is a list of CVE (security) URLs */
+		gpk_update_viewer_add_description_link_item (_("For more information about this security update please visit:"), obj->cve_url);
+	}
+
+	/* reboot */
+	if (obj->restart == PK_RESTART_ENUM_SESSION ||
+	    obj->restart == PK_RESTART_ENUM_SYSTEM) {
+		info_text = gpk_restart_enum_to_localised_text (obj->restart);
+		/* TRANSLATORS: this is a notice a restart might be required */
+		gpk_update_viewer_add_description_item (_("Notice"), info_text);
+	}
+}
+
+/**
+ * pk_packages_treeview_clicked_cb:
+ **/
+static void
+pk_packages_treeview_clicked_cb (GtkTreeSelection *selection, gpointer data)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *package_id;
+	PkUpdateDetailObj *obj = NULL;
+
+	/* 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,
+				    GPK_UPDATES_COLUMN_UPDATE_DETAIL_OBJ, &obj,
+				    GPK_UPDATES_COLUMN_ID, &package_id, -1);
+
+		egg_debug ("selected row is: %s, %p", package_id, obj);
+		g_free (package_id);
+		if (obj != NULL)
+			gpk_update_viewer_populate_details (obj);
+	} else {
+		egg_debug ("no row selected");
+	}
+}
+
+/**
+ * gpk_update_viewer_check_blocked_packages:
+ **/
+static void
+gpk_update_viewer_check_blocked_packages (PkPackageList *list)
+{
+	guint i;
+	guint length;
+	const PkPackageObj *obj;
+	GString *string;
+	gboolean exists = FALSE;
+	gchar *text;
+	GtkWidget *widget;
+
+	string = g_string_new ("");
+
+	/* find any that are blocked */
+	length = pk_package_list_get_size (list);
+	for (i=0;i<length;i++) {
+		obj = pk_package_list_get_obj (list, i);
+		if (obj->info == PK_INFO_ENUM_BLOCKED) {
+			text = gpk_package_id_format_oneline (obj->id, obj->summary);
+			g_string_append_printf (string, "%s\n", text);
+			g_free (text);
+			exists = TRUE;
+		}
+	}
+
+	/* trim off extra newlines */
+	if (string->len != 0)
+		g_string_set_size (string, string->len-1);
+
+	/* convert to a normal gchar */
+	text = g_string_free (string, FALSE);
+
+	/* nothing of interest */
+	if (!exists)
+		goto out;
+
+	/* throw up dialog */
+	widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+	gpk_error_dialog_modal (GTK_WINDOW (widget), _("Some updates were not installed"), text, NULL);
+out:
+	g_free (text);
+}
+
+/**
+ * gpk_update_viewer_finished_get_details_cb:
+ **/
+static gboolean
+gpk_update_viewer_finished_get_details_cb (PkPackageList *list)
+{
+	gboolean ret;
+	gchar **package_ids;
+	GError *error = NULL;
+	package_ids = pk_package_list_to_strv (list);
+
+	/* get the details of all the packages */
+	ret = pk_client_reset (client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	ret = pk_client_get_details (client_primary, package_ids, &error);
+	if (!ret) {
+		egg_error ("cannot get details: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
+	g_object_unref (list);
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_finished_get_update_details_cb:
+ **/
+static gboolean
+gpk_update_viewer_finished_get_update_details_cb (PkPackageList *list)
+{
+	gboolean ret;
+	gchar **package_ids;
+	GError *error = NULL;
+	package_ids = pk_package_list_to_strv (list);
+
+	/* get the details of all the packages */
+	ret = pk_client_reset (client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	ret = pk_client_get_update_detail (client_primary, package_ids, &error);
+	if (!ret) {
+		egg_error ("cannot get details: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	g_strfreev (package_ids);
+	g_object_unref (list);
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_finished_get_distro_upgrades_cb:
+ **/
+static gboolean
+gpk_update_viewer_finished_get_distro_upgrades_cb (gpointer data)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* get the details of all the packages */
+	ret = pk_client_reset (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 (client_primary, &error);
+	if (!ret) {
+		egg_error ("cannot get details: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_requeue:
+ **/
+static gboolean
+gpk_update_viewer_requeue (gpointer data)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* retry new action */
+	ret = pk_client_requeue (client_primary, &error);
+	if (!ret) {
+		egg_warning ("Failed to requeue: %s", error->message);
+		g_error_free (error);
+	}
+	return ret;
+}
+
+/**
+ * gpk_update_viewer_finished_cb:
+ **/
+static void
+gpk_update_viewer_finished_cb (PkClient *client, PkExitEnum exit, guint runtime, gpointer data)
+{
+	GtkWidget *widget;
+	GtkTreePath *path;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	PkRoleEnum role;
+	PkPackageList *list;
+
+	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));
+
+	/* clear package */
+	widget = glade_xml_get_widget (glade_xml, "label_package");
+	gtk_label_set_label (GTK_LABEL (widget), "");
+
+	widget = glade_xml_get_widget (glade_xml, "progressbar_progress");
+	gtk_widget_hide (widget);
+
+	/* if secondary, ignore */
+	if (client == client_primary &&
+	    (exit == PK_EXIT_ENUM_KEY_REQUIRED ||
+	     exit == PK_EXIT_ENUM_EULA_REQUIRED)) {
+		egg_debug ("ignoring primary sig-required or eula");
+		return;
+	}
+
+	/* get model */
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	/* clicked cancel on get updates screen */
+	if (role == PK_ROLE_ENUM_GET_UPDATES &&
+	    exit == PK_EXIT_ENUM_CANCELLED) {
+		g_main_loop_quit (loop);
+		return;
+	}
+
+	if (role == PK_ROLE_ENUM_GET_UPDATES) {
+		/* get the download sizes */
+		if (update_list != NULL)
+			g_object_unref (update_list);
+		update_list = pk_client_get_package_list (client_primary);
+
+		/* get the download sizes */
+		if (PK_OBJ_LIST(update_list)->len > 0)
+			g_idle_add ((GSourceFunc) gpk_update_viewer_finished_get_update_details_cb, g_object_ref (update_list));
+
+		/* set info */
+		gpk_update_viewer_reconsider_info (model);
+	}
+
+	if (role == PK_ROLE_ENUM_GET_UPDATE_DETAIL) {
+		/* get the restarts */
+		g_idle_add ((GSourceFunc) gpk_update_viewer_finished_get_details_cb, g_object_ref (update_list));
+
+		/* are now able to do action */
+		widget = glade_xml_get_widget (glade_xml, "button_install");
+		gtk_widget_set_sensitive (widget, TRUE);
+
+		/* set info */
+		gpk_update_viewer_reconsider_info (model);
+	}
+
+	if (role == PK_ROLE_ENUM_GET_DETAILS) {
+		/* get the distro-upgrades */
+		g_idle_add ((GSourceFunc) gpk_update_viewer_finished_get_distro_upgrades_cb, NULL);
+
+		/* select the first entry in the updates list now we've got data */
+		widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+		gtk_tree_selection_unselect_all (selection);
+		path = gtk_tree_path_new_first ();
+		gtk_tree_selection_select_path (selection, path);
+		gtk_tree_path_free (path);
+
+		/* set info */
+		gpk_update_viewer_reconsider_info (model);
+	}
+
+	/* we've just agreed to auth or a EULA */
+	if (role == PK_ROLE_ENUM_INSTALL_SIGNATURE ||
+	    role == PK_ROLE_ENUM_ACCEPT_EULA) {
+		if (exit == PK_EXIT_ENUM_SUCCESS)
+			gpk_update_viewer_requeue (NULL);
+		else
+			gpk_update_viewer_undisable_packages ();
+	}
+
+	/* check if we need to display infomation about blocked packages */
+	if (exit == PK_EXIT_ENUM_SUCCESS &&
+	    (role == PK_ROLE_ENUM_UPDATE_SYSTEM ||
+	     role == PK_ROLE_ENUM_UPDATE_PACKAGES)) {
+
+		/* check blocked */
+		list = pk_client_get_package_list (client_primary);
+		gpk_update_viewer_check_blocked_packages (list);
+		g_object_unref (list);
+
+		/* refresh list */
+		gpk_update_viewer_get_new_update_list ();
+	}
+
+	/* we pressed cancel */
+	if (exit != PK_EXIT_ENUM_SUCCESS) {
+		gpk_update_viewer_undisable_packages ();
+	}
+}
+
+/**
+ * gpk_update_viewer_progress_changed_cb:
+ **/
+static void
+gpk_update_viewer_progress_changed_cb (PkClient *client, guint percentage, guint subpercentage,
+				guint elapsed, guint remaining, gpointer data)
+{
+	GtkWidget *widget;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	widget = glade_xml_get_widget (glade_xml, "progressbar_progress");
+	gtk_widget_show (widget);
+	if (percentage != PK_CLIENT_PERCENTAGE_INVALID)
+		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widget), (gfloat) percentage / 100.0);
+
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	if (package_id_last == NULL) {
+		egg_debug ("no last package");
+		return;
+	}
+
+	path = gpk_update_viewer_model_get_path (model, package_id_last);
+	if (path == NULL) {
+		egg_debug ("not found ID for package");
+		return;
+	}
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	gtk_list_store_set (list_store_updates, &iter,
+			    GPK_UPDATES_COLUMN_PERCENTAGE, subpercentage, -1);
+}
+
+/**
+ * gpk_update_viewer_error_code_cb:
+ **/
+static void
+gpk_update_viewer_error_code_cb (PkClient *client, PkErrorCodeEnum code, const gchar *details, gpointer data)
+{
+	GtkWidget *widget;
+
+	/* 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 ||
+	    code == PK_ERROR_ENUM_NO_LICENSE_AGREEMENT) {
+		egg_debug ("error ignored as we're handling %s\n%s", pk_error_enum_to_text (code), details);
+		return;
+	}
+
+	widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+	gpk_error_dialog_modal (GTK_WINDOW (widget), gpk_error_enum_to_localised_text (code),
+				gpk_error_enum_to_localised_message (code), details);
+}
+
+/**
+ * gpk_update_viewer_repo_list_changed_cb:
+ **/
+static void
+gpk_update_viewer_repo_list_changed_cb (PkClient *client, gpointer data)
+{
+	gpk_update_viewer_get_new_update_list ();
+}
+
+/**
+ * gpk_update_viewer_detail_popup_menu_select_all:
+ **/
+static void
+gpk_update_viewer_detail_popup_menu_select_all (GtkWidget *menuitem, gpointer userdata)
+{
+	GtkTreeView *treeview = GTK_TREE_VIEW (userdata);
+	gboolean valid;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	PkStatusEnum info;
+
+	/* get the first iter in the list */
+	model = gtk_tree_view_get_model (treeview);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid) {
+		gtk_tree_model_get (model, &iter, GPK_UPDATES_COLUMN_INFO, &info, -1);
+		if (info != PK_INFO_ENUM_BLOCKED)
+			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+					    GPK_UPDATES_COLUMN_SELECT, TRUE, -1);
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	/* if there are no entries selected, deselect the button */
+	gpk_update_viewer_reconsider_info (model);
+}
+
+/**
+ * gpk_update_viewer_detail_popup_menu_select_none:
+ **/
+static void
+gpk_update_viewer_detail_popup_menu_select_none (GtkWidget *menuitem, gpointer userdata)
+{
+	GtkTreeView *treeview = GTK_TREE_VIEW (userdata);
+	gboolean valid;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	/* get the first iter in the list */
+	model = gtk_tree_view_get_model (treeview);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	while (valid) {
+		gtk_tree_model_get (model, &iter, -1);
+		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+				    GPK_UPDATES_COLUMN_SELECT, FALSE, -1);
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	/* if there are no entries selected, deselect the button */
+	gpk_update_viewer_reconsider_info (model);
+}
+
+/**
+ * gpk_update_viewer_get_checked_status:
+ **/
+static void
+gpk_update_viewer_get_checked_status (gboolean *all_checked, gboolean *none_checked)
+{
+	GtkTreeView *treeview;
+	gboolean valid;
+	gboolean update;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	/* get the first iter in the list */
+	treeview = GTK_TREE_VIEW (glade_xml_get_widget (glade_xml, "treeview_updates"));
+	model = gtk_tree_view_get_model (treeview);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	*all_checked = TRUE;
+	*none_checked = TRUE;
+	while (valid) {
+		gtk_tree_model_get (model, &iter, GPK_UPDATES_COLUMN_SELECT, &update, -1);
+		if (update)
+			*none_checked = FALSE;
+		else
+			*all_checked = FALSE;
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+}
+
+/**
+ * gpk_update_viewer_detail_popup_menu_create:
+ **/
+static void
+gpk_update_viewer_detail_popup_menu_create (GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
+{
+	GtkWidget *menu;
+	GtkWidget *menuitem;
+	gboolean all_checked;
+	gboolean none_checked;
+
+	menu = gtk_menu_new();
+
+	/* we don't want to show 'Select all' if they are all checked */
+	gpk_update_viewer_get_checked_status (&all_checked, &none_checked);
+
+	if (!all_checked) {
+		/* TRANSLATORS: right click menu, select all the updates */
+		menuitem = gtk_menu_item_new_with_label (_("Select all"));
+		g_signal_connect (menuitem, "activate",
+				  G_CALLBACK (gpk_update_viewer_detail_popup_menu_select_all), treeview);
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+	}
+
+	if (!none_checked) {
+		/* TRANSLATORS: right click menu, unselect all the updates */
+		menuitem = gtk_menu_item_new_with_label (_("Unselect all"));
+		g_signal_connect (menuitem, "activate",
+				  G_CALLBACK (gpk_update_viewer_detail_popup_menu_select_none), treeview);
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+	}
+
+	/* TRANSLATORS: right click option, ignore this update name, not currently used */
+	menuitem = gtk_menu_item_new_with_label (_("Ignore this update"));
+	gtk_widget_set_sensitive (GTK_WIDGET (menuitem), FALSE);
+	g_signal_connect (menuitem, "activate",
+			  G_CALLBACK (gpk_update_viewer_detail_popup_menu_select_all), treeview);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+
+	gtk_widget_show_all (menu);
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
+		        (event != NULL) ? event->button : 0,
+		        gdk_event_get_time((GdkEvent*)event));
+}
+
+/**
+ * gpk_update_viewer_detail_button_pressed:
+ **/
+static gboolean
+gpk_update_viewer_detail_button_pressed (GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
+{
+	GtkTreeSelection *selection;
+	GtkTreePath *path;
+
+	/* single click with the right mouse button? */
+	if (event->type != GDK_BUTTON_PRESS || event->button != 3) {
+		/* we did not handle this */
+		return FALSE;
+	}
+
+	egg_debug ("Single right click on the tree view");
+
+	/* select the row */
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+	if (gtk_tree_selection_count_selected_rows (selection) <= 1) {
+		/* Get tree path for row that was clicked */
+		if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
+						   (gint) event->x, (gint) event->y, &path,
+						   NULL, NULL, NULL)) {
+			gtk_tree_selection_unselect_all (selection);
+			gtk_tree_selection_select_path (selection, path);
+			gtk_tree_path_free (path);
+		}
+	}
+
+	/* create */
+	gpk_update_viewer_detail_popup_menu_create (treeview, event, userdata);
+	return TRUE;
+}
+
+/**
+ * gpk_update_viewer_detail_popup_menu:
+ **/
+static gboolean
+gpk_update_viewer_detail_popup_menu (GtkWidget *treeview, gpointer userdata)
+{
+	gpk_update_viewer_detail_popup_menu_create (treeview, NULL, userdata);
+	return TRUE;
+}
+
+/**
+ * gpk_update_viewer_activated_cb
+ **/
+static void
+gpk_update_viewer_activated_cb (EggUnique *egg_unique, gpointer data)
+{
+	GtkWidget *widget;
+	widget = glade_xml_get_widget (glade_xml, "dialog_updates");
+	gtk_window_present (GTK_WINDOW (widget));
+}
+
+/**
+ * gpk_update_viewer_get_new_update_list
+ **/
+static gboolean
+gpk_update_viewer_get_new_update_list (void)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	/* clear all widgets */
+	gtk_list_store_clear (list_store_updates);
+	gtk_list_store_clear (list_store_details);
+	gtk_text_buffer_set_text (text_buffer, "", -1);
+
+	/* reset client */
+	ret = pk_client_reset (client_primary, &error);
+	if (!ret) {
+		egg_warning ("cannot reset client: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get new list */
+	ret = pk_client_get_updates (client_primary, PK_FILTER_ENUM_NONE, &error);
+	if (!ret) {
+		egg_warning ("Failed to get updates: %s", error->message);
+		g_error_free (error);
+	}
+out:
+	return ret;
+}
+
+/**
+ * gpk_update_viewer_allow_cancel_cb:
+ **/
+static void
+gpk_update_viewer_allow_cancel_cb (PkClient *client, gboolean allow_cancel, gpointer data)
+{
+	GtkWidget *widget;
+	widget = glade_xml_get_widget (glade_xml, "button_cancel");
+	gtk_widget_set_sensitive (widget, allow_cancel);
+}
+
+/**
+ * gpk_update_viewer_eula_cb:
+ **/
+static void
+gpk_update_viewer_eula_required_cb (PkClient *client, const gchar *eula_id, const gchar *package_id,
+				    const gchar *vendor_name, const gchar *license_agreement, gpointer data)
+{
+	/* use the helper */
+	gpk_eula_helper_show (eula_helper, eula_id, package_id, vendor_name, license_agreement);
+}
+
+/**
+ * gpk_update_viewer_repo_signature_event_cb:
+ **/
+static void
+gpk_update_viewer_repo_signature_event_cb (GpkRepoSignatureHelper *_repo_signature_helper, GtkResponseType type, const gchar *key_id, const gchar *package_id, gpointer data)
+{
+	GtkWidget *widget;
+	GtkTreeModel *model;
+	gboolean ret;
+	GError *error = NULL;
+
+	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;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (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 (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);
+		/* we've ruined the old one by making the checkboxes insensitive */
+		gpk_update_viewer_get_new_update_list ();
+		goto out;
+	}
+out:
+	/* set state */
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	gpk_update_viewer_reconsider_info (model);
+}
+
+/**
+ * gpk_update_viewer_eula_event_cb:
+ **/
+static void
+gpk_update_viewer_eula_event_cb (GpkRepoSignatureHelper *_eula_helper, GtkResponseType type, const gchar *eula_id, gpointer data)
+{
+	GtkWidget *widget;
+	GtkTreeModel *model;
+	gboolean ret;
+	GError *error = NULL;
+
+	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;
+	}
+
+	/* reset client */
+	ret = pk_client_reset (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 (client_secondary, eula_id, &error);
+	if (!ret) {
+		egg_warning ("cannot accept eula: %s", error->message);
+		g_error_free (error);
+		/* we've ruined the old one by making the checkboxes insensitive */
+		gpk_update_viewer_get_new_update_list ();
+		goto out;
+	}
+out:
+	/* set state */
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	gpk_update_viewer_reconsider_info (model);
+}
+
+/**
+ * gpk_update_viewer_repo_signature_required_cb:
+ **/
+static void
+gpk_update_viewer_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, gpointer data)
+{
+	/* use the helper */
+	gpk_repo_signature_helper_show (repo_signature_helper, package_id, repository_name, key_url, key_userid, key_id, key_fingerprint, key_timestamp);
+}
+
+/**
+ * pk_client_distro_upgrade_cb:
+ **/
+static void
+pk_client_distro_upgrade_cb (PkClient *client, const PkDistroUpgradeObj *obj, gpointer data)
+{
+	gchar *text;
+	gchar *text_format;
+	GtkWidget *widget;
+
+	if (obj->state != PK_UPDATE_STATE_ENUM_STABLE)
+		return;
+
+	/* only display last (newest) distro */
+	widget = glade_xml_get_widget (glade_xml, "label_upgrade");
+	text = g_strdup_printf (_("New distribution upgrade release '%s' is available"), obj->summary);
+	text_format = g_strdup_printf ("<b>%s</b>", text);
+	gtk_label_set_label (GTK_LABEL (widget), text_format);
+	g_free (text);
+	g_free (text_format);
+	widget = glade_xml_get_widget (glade_xml, "viewport_upgrade");
+	gtk_widget_show (widget);
+}
+
+/**
+ * gpk_update_viewer_textview_follow_link:
+ *
+ * Looks at all tags covering the position of iter in the text view,
+ * and if one of them is a link, follow it by showing the page identified
+ * by the data attached to it.
+ **/
+static void
+gpk_update_viewer_textview_follow_link (GtkWidget *text_view, GtkTextIter *iter)
+{
+	GSList *tags = NULL, *tagp = NULL;
+
+	tags = gtk_text_iter_get_tags (iter);
+	for (tagp = tags; tagp != NULL; tagp = tagp->next) {
+		GtkTextTag *tag = tagp->data;
+		const gchar *href = (const gchar *) (g_object_get_data (G_OBJECT (tag), "href"));
+		gpk_gnome_open (href);
+	}
+
+	if (tags != NULL)
+		g_slist_free (tags);
+}
+
+/**
+ * gpk_update_viewer_textview_key_press_event:
+ *
+ * Links can be activated by pressing Enter
+ **/
+static gboolean
+gpk_update_viewer_textview_key_press_event (GtkWidget *text_view, GdkEventKey *event)
+{
+	GtkTextIter iter;
+	GtkTextBuffer *buffer;
+
+	switch (event->keyval) {
+		case GDK_Return:
+		case GDK_KP_Enter:
+			buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+			gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
+			gpk_update_viewer_textview_follow_link (text_view, &iter);
+			break;
+		default:
+		break;
+	}
+
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_textview_event_after:
+ *
+ * Links can also be activated by clicking
+ **/
+static gboolean
+gpk_update_viewer_textview_event_after (GtkWidget *text_view, GdkEvent *ev)
+{
+	GtkTextIter start, end, iter;
+	GtkTextBuffer *buffer;
+	GdkEventButton *event;
+	gint x, y;
+
+	if (ev->type != GDK_BUTTON_RELEASE)
+		return FALSE;
+
+	event = (GdkEventButton *)ev;
+	if (event->button != 1)
+		return FALSE;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+	/* we shouldn't follow a link if the user has selected something */
+	gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+	if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
+		return FALSE;
+
+	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y);
+	gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
+	gpk_update_viewer_textview_follow_link (text_view, &iter);
+
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_textview_set_cursor:
+ *
+ * Looks at all tags covering the position (x, y) in the text view,
+ * and if one of them is a link, change the cursor to the "hands" cursor
+ * typically used by web browsers.
+ **/
+static void
+gpk_update_viewer_textview_set_cursor (GtkTextView *text_view, gint x, gint y)
+{
+	GSList *tags = NULL, *tagp = NULL;
+	GtkTextIter iter;
+	GdkCursor *cursor;
+	gboolean hovering = FALSE;
+	gboolean hovering_over_link = FALSE;
+
+	hovering_over_link = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(text_view), "hovering"));
+	gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
+
+	tags = gtk_text_iter_get_tags (&iter);
+	for (tagp = tags; tagp != NULL; tagp = tagp->next) {
+		GtkTextTag *tag = tagp->data;
+		const gchar *href = (const gchar *) g_object_get_data (G_OBJECT (tag), "href");
+		if (href != NULL) {
+			hovering = TRUE;
+			break;
+		}
+	}
+
+	/* already set same state */
+	if (hovering != hovering_over_link) {
+		g_object_set_data (G_OBJECT(text_view), "hovering", GUINT_TO_POINTER (hovering));
+		if (hovering)
+			cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_HAND2);
+		else
+			cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_XTERM);
+		gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), cursor);
+		gdk_cursor_unref (cursor);
+	}
+
+	if (tags != NULL)
+		g_slist_free (tags);
+}
+
+/**
+ * gpk_update_viewer_textview_motion_notify_event:
+ *
+ * Update the cursor image if the pointer moved.
+ **/
+static gboolean
+gpk_update_viewer_textview_motion_notify_event (GtkWidget *text_view, GdkEventMotion *event)
+{
+	gint x, y;
+
+	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y);
+	gpk_update_viewer_textview_set_cursor (GTK_TEXT_VIEW (text_view), x, y);
+	gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
+	return FALSE;
+}
+
+/**
+ * gpk_update_viewer_textview_visibility_notify_event:
+ *
+ * Also update the cursor image if the window becomes visible
+ * (e.g. when a window covering it got iconified).
+ **/
+static gboolean
+gpk_update_viewer_textview_visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event)
+{
+	gint wx, wy, bx, by;
+
+	gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
+	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by);
+	gpk_update_viewer_textview_set_cursor (GTK_TEXT_VIEW (text_view), bx, by);
+	return FALSE;
+}
+
+/**
+ * main:
+ **/
+int
+main (int argc, char *argv[])
+{
+	gboolean verbose = FALSE;
+	gboolean program_version = FALSE;
+	GOptionContext *context;
+	GtkWidget *main_window;
+	GtkWidget *widget;
+	GtkTreeSelection *selection;
+	PkBitfield roles;
+	gboolean ret;
+	GError *error = NULL;
+	EggUnique *egg_unique;
+
+	const GOptionEntry options[] = {
+		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+		  _("Show extra debugging information"), NULL },
+		{ "version", '\0', 0, G_OPTION_ARG_NONE, &program_version,
+		  _("Show the program version and exit"), NULL },
+		{ NULL}
+	};
+
+	setlocale (LC_ALL, "");
+
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	if (! g_thread_supported ())
+		g_thread_init (NULL);
+	dbus_g_thread_init ();
+	g_type_init ();
+
+	context = g_option_context_new (NULL);
+	/* TRANSLATORS: program name, a simple app to view pending updates */
+	g_option_context_set_summary (context, _("Software Update Viewer"));
+	g_option_context_add_main_entries (context, options, NULL);
+	g_option_context_parse (context, &argc, &argv, NULL);
+	g_option_context_free (context);
+
+	if (program_version) {
+		g_print (VERSION "\n");
+		return 0;
+	}
+
+	egg_debug_init (verbose);
+	notify_init ("gpk-update-viewer");
+	gtk_init (&argc, &argv);
+
+	/* TRANSLATORS: title to pass to to the user if there are not enough privs */
+	ret = gpk_check_privileged_user (_("Software Update Viewer"), TRUE);
+	if (!ret)
+		return 1;
+
+	/* 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");
+
+	/* are we already activated? */
+	egg_unique = egg_unique_new ();
+	ret = egg_unique_assign (egg_unique, "org.freedesktop.PackageKit.UpdateViewer2");
+	if (!ret)
+		goto unique_out;
+
+	g_signal_connect (egg_unique, "activated", G_CALLBACK (gpk_update_viewer_activated_cb), NULL);
+
+	markdown = egg_markdown_new ();
+	egg_markdown_set_output (markdown, EGG_MARKDOWN_OUTPUT_PANGO);
+	egg_markdown_set_escape (markdown, TRUE);
+
+	control = pk_control_new ();
+	g_signal_connect (control, "repo-list-changed",
+			  G_CALLBACK (gpk_update_viewer_repo_list_changed_cb), NULL);
+
+	/* this is what we use mainly */
+	client_primary = pk_client_new ();
+	pk_client_set_use_buffer (client_primary, TRUE, NULL);
+	g_signal_connect (client_primary, "package",
+			  G_CALLBACK (gpk_update_viewer_package_cb), NULL);
+	g_signal_connect (client_primary, "details",
+			  G_CALLBACK (gpk_update_viewer_details_cb), NULL);
+	g_signal_connect (client_primary, "finished",
+			  G_CALLBACK (gpk_update_viewer_finished_cb), NULL);
+	g_signal_connect (client_primary, "progress-changed",
+			  G_CALLBACK (gpk_update_viewer_progress_changed_cb), NULL);
+	g_signal_connect (client_primary, "update-detail",
+			  G_CALLBACK (gpk_update_viewer_update_detail_cb), NULL);
+	g_signal_connect (client_primary, "status-changed",
+			  G_CALLBACK (gpk_update_viewer_status_changed_cb), NULL);
+	g_signal_connect (client_primary, "error-code",
+			  G_CALLBACK (gpk_update_viewer_error_code_cb), NULL);
+	g_signal_connect (client_primary, "allow-cancel",
+			  G_CALLBACK (gpk_update_viewer_allow_cancel_cb), NULL);
+	g_signal_connect (client_primary, "repo-signature-required",
+			  G_CALLBACK (gpk_update_viewer_repo_signature_required_cb), NULL);
+	g_signal_connect (client_primary, "eula-required",
+			  G_CALLBACK (gpk_update_viewer_eula_required_cb), NULL);
+	g_signal_connect (client_primary, "distro-upgrade",
+			  G_CALLBACK (pk_client_distro_upgrade_cb), NULL);
+
+	/* this is for auth and eula callbacks */
+	client_secondary = pk_client_new ();
+	g_signal_connect (client_secondary, "error-code",
+			  G_CALLBACK (gpk_update_viewer_error_code_cb), NULL);
+	g_signal_connect (client_secondary, "finished",
+			  G_CALLBACK (gpk_update_viewer_finished_cb), NULL);
+
+	/* get actions */
+	roles = pk_control_get_actions (control, NULL);
+
+	glade_xml = glade_xml_new (GPK_DATA "/gpk-update-viewer2.glade", NULL, NULL);
+	main_window = glade_xml_get_widget (glade_xml, "dialog_updates");
+	g_signal_connect (main_window, "delete_event", G_CALLBACK (gpk_update_viewer_button_delete_event_cb), NULL);
+
+	/* helpers */
+	repo_signature_helper = gpk_repo_signature_helper_new ();
+	g_signal_connect (repo_signature_helper, "event", G_CALLBACK (gpk_update_viewer_repo_signature_event_cb), NULL);
+	gpk_repo_signature_helper_set_parent (repo_signature_helper, GTK_WINDOW (main_window));
+
+	eula_helper = gpk_eula_helper_new ();
+	g_signal_connect (eula_helper, "event", G_CALLBACK (gpk_update_viewer_eula_event_cb), NULL);
+	gpk_eula_helper_set_parent (eula_helper, GTK_WINDOW (main_window));
+
+	/* make GpkClient windows modal */
+	gtk_widget_realize (main_window);
+
+	/* create list stores */
+	list_store_updates = gtk_list_store_new (GPK_UPDATES_COLUMN_LAST, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
+						 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+						 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
+	list_store_details = gtk_list_store_new (GPK_DESC_COLUMN_LAST, G_TYPE_STRING, G_TYPE_STRING);
+	text_buffer = gtk_text_buffer_new (NULL);
+
+	/* no upgrades yet */
+	widget = glade_xml_get_widget (glade_xml, "viewport_upgrade");
+	gtk_widget_hide (widget);
+
+	/* header */
+	widget = glade_xml_get_widget (glade_xml, "hbox_header");
+	gtk_widget_hide (widget);
+
+	/* description */
+	widget = glade_xml_get_widget (glade_xml, "textview_details");
+	gtk_text_view_set_buffer (GTK_TEXT_VIEW (widget), text_buffer);
+	gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), FALSE);
+	g_signal_connect (GTK_TEXT_VIEW (widget), "key-press-event", G_CALLBACK (gpk_update_viewer_textview_key_press_event), NULL);
+	g_signal_connect (GTK_TEXT_VIEW (widget), "event-after", G_CALLBACK (gpk_update_viewer_textview_event_after), NULL);
+	g_signal_connect (GTK_TEXT_VIEW (widget), "motion-notify-event", G_CALLBACK (gpk_update_viewer_textview_motion_notify_event), NULL);
+	g_signal_connect (GTK_TEXT_VIEW (widget), "visibility-notify-event", G_CALLBACK (gpk_update_viewer_textview_visibility_notify_event), NULL);
+
+	/* updates */
+	widget = glade_xml_get_widget (glade_xml, "treeview_updates");
+	gtk_widget_set_size_request (GTK_WIDGET (widget), 800, 200);
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (list_store_updates));
+	gpk_update_viewer_treeview_add_columns_update (GTK_TREE_VIEW (widget));
+	g_signal_connect (widget, "popup-menu",
+			  G_CALLBACK (gpk_update_viewer_detail_popup_menu), NULL);
+	g_signal_connect (widget, "button-press-event",
+			  G_CALLBACK (gpk_update_viewer_detail_button_pressed), NULL);
+
+	/* selection */
+	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);
+
+	/* details */
+	widget = glade_xml_get_widget (glade_xml, "vbox_details");
+	gtk_widget_set_size_request (GTK_WIDGET (widget), 500, 200);
+	widget = glade_xml_get_widget (glade_xml, "treeview_details");
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (list_store_details));
+	gpk_update_viewer_treeview_add_columns_details (GTK_TREE_VIEW (widget));
+
+	widget = glade_xml_get_widget (glade_xml, "progressbar_progress");
+	gtk_widget_hide (widget);
+	widget = glade_xml_get_widget (glade_xml, "label_summary");
+	gtk_widget_hide (widget);
+
+	/* help button */
+	widget = glade_xml_get_widget (glade_xml, "button_help");
+	g_signal_connect (widget, "clicked",
+			  G_CALLBACK (gpk_update_viewer_button_help_cb), (gpointer) "update-viewer");
+
+	/* set install button insensitive */
+	widget = glade_xml_get_widget (glade_xml, "button_install");
+	gtk_widget_set_sensitive (widget, FALSE);
+	g_signal_connect (widget, "clicked",
+			  G_CALLBACK (gpk_update_viewer_button_install_cb), NULL);
+
+	/* close button */
+	widget = glade_xml_get_widget (glade_xml, "button_close");
+	g_signal_connect (widget, "clicked",
+			  G_CALLBACK (gpk_update_viewer_button_close_cb), NULL);
+	gtk_widget_hide (widget);
+	gtk_window_set_focus (GTK_WINDOW(main_window), widget);
+
+	/* hide cancel button */
+	widget = glade_xml_get_widget (glade_xml, "button_cancel");
+	gtk_widget_hide (widget);
+	g_signal_connect (widget, "clicked",
+			  G_CALLBACK (gpk_update_viewer_button_cancel_cb), NULL);
+
+	/* upgrade button */
+	widget = glade_xml_get_widget (glade_xml, "button_upgrade");
+	g_signal_connect (widget, "clicked",
+			  G_CALLBACK (gpk_update_viewer_button_upgrade_cb), NULL);
+
+	/* show window */
+	gtk_widget_show (main_window);
+
+	/* coldplug */
+	gpk_update_viewer_get_new_update_list ();
+
+	/* wait */
+	loop = g_main_loop_new (NULL, FALSE);
+	g_main_loop_run (loop);
+
+	/* we might have visual stuff running, close it down */
+	ret = pk_client_cancel (client_primary, &error);
+	if (!ret) {
+		egg_warning ("failed to cancel client: %s", error->message);
+		g_clear_error (&error);
+	}
+
+	/* we might have visual stuff running, close it down */
+	ret = pk_client_cancel (client_secondary, &error);
+	if (!ret) {
+		egg_warning ("failed to cancel client: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_main_loop_unref (loop);
+
+	if (update_list != NULL)
+		g_object_unref (update_list);
+
+	g_object_unref (eula_helper);
+	g_object_unref (repo_signature_helper);
+	g_object_unref (glade_xml);
+	g_object_unref (list_store_details);
+	g_object_unref (list_store_updates);
+	g_object_unref (control);
+	g_object_unref (markdown);
+	g_object_unref (client_primary);
+	g_object_unref (client_secondary);
+	g_object_unref (text_buffer);
+	pk_package_id_free (package_id_last);
+unique_out:
+	g_object_unref (egg_unique);
+
+	return 0;
+}
+



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