Index: gnome-cups-manager/gnome-printer-list.c
===================================================================
RCS file: /cvs/gnome/gnome-cups-manager/gnome-cups-manager/gnome-printer-list.c,v
retrieving revision 1.13
diff -p -u -B -r1.13 gnome-printer-list.c
--- gnome-cups-manager/gnome-printer-list.c	28 Feb 2005 19:05:22 -0000	1.13
+++ gnome-cups-manager/gnome-printer-list.c	14 Dec 2006 14:58:21 -0000
@@ -2,6 +2,7 @@
 /* 
  * gnome-printer-list.c
  * Copyright (C) 2003-2004, Ximian, Inc.
+ * Copyright (C) 2006 Christian Persch
  *
  * Authors:
  *   Dave Camp <dave@ximian.com>
@@ -25,28 +26,40 @@
 #include <config.h>
 
 #include "gnome-printer-list.h"
+#include "gnome-printers-model.h"
 
 #include "printer-properties.h"
 #include "view-queue.h"
 
+#include <glib.h>
+#include <glib/gi18n.h>
 #include <gtk/gtkmenu.h>
 #include <gtk/gtkimagemenuitem.h>
 #include <gtk/gtkseparatormenuitem.h>
 #include <gtk/gtkstock.h>
 #include <gtk/gtkicontheme.h>
-#include <glib.h>
-#include <glib/gi18n.h>
+#include <gtk/gtksettings.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreesortable.h>
+#include <gtk/gtktreemodelsort.h>
+#include <gtk/gtkcellrenderer.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrendererpixbuf.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkiconfactory.h>
+#include <gtk/gtkmain.h>
 
 #include <libgnomecups/gnome-cups-printer.h>
 #include <libgnomecups/gnome-cups-ui-util.h>
 #include <libgnomecups/gnome-cups-permission.h>
 
 struct _GnomePrinterListDetails {
-	EggIconListItem *add_item;
+	GnomePrintersModel *printers_model;
+	GtkTreeModel *tree_model;
+	GtkTreeModel *sort_model;
 
-	GList *printers;
-	
-	guint new_printer_notify;
+	guint printer_added_id;
+	guint printer_removed_id;
 };
 
 /* Tool to help debug lifecycle */
@@ -56,197 +69,372 @@ struct _GnomePrinterListDetails {
 #define d(code)
 #endif
 
-static void disconnect_printer (GnomePrinterList *list, GnomeCupsPrinter *printer);
+G_DEFINE_TYPE (GnomePrinterList, gnome_printer_list, GTK_TYPE_ICON_VIEW);
 
-G_DEFINE_TYPE (GnomePrinterList, gnome_printer_list, egg_icon_list_get_type ())
-
-static GdkPixbuf *
-load_icon (GtkWidget *w, char const *icon_name)
+static void
+printer_get_pixbuf_func (GtkCellLayout *cell_layout,
+			 GtkCellRenderer *cell,
+			 GtkTreeModel *model,
+			 GtkTreeIter *iter,
+			 gpointer data)
 {
-	GError *err = NULL;
-	GdkPixbuf *res = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-		icon_name, 48, 0, NULL);
-
-	if (res == NULL) {
-		if (err != NULL) {
-			g_warning ("%s", err->message);
-			g_error_free (err);
-			err = NULL;
-		}
-		res = gtk_widget_render_icon (w, icon_name, GTK_ICON_SIZE_DIALOG, NULL);
+	GtkWidget *widget;
+	GnomeCupsPrinter *printer = NULL;
+	GdkPixbuf *pixbuf;
+	GtkIconTheme *icon_theme;
+	char *icon_name = NULL;
+	GList *ptr, *emblems = NULL;
+	int width, height;
+
+	gtk_tree_model_get (model,
+			    iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	d(g_print ("Getting pixbuf for printer %s\n", printer ? gnome_cups_printer_get_name (printer) : "NEW-PRINTER"););
+
+	if (printer == NULL) {
+		g_object_set (cell,
+			      "pixbuf", NULL,
+			      "icon-name", "gnome-dev-printer-new",
+			      NULL);
+		return;
+	}
 
-		if (err != NULL) {
-			g_warning ("%s", err->message);
-			g_error_free (err);
-			return NULL;
-		}
+	gnome_cups_printer_get_icon (printer,
+				     &icon_name,
+				     &emblems);
+	if (emblems == NULL) {
+		g_object_set (cell,
+			      "pixbuf", NULL,
+			      "icon-name", icon_name,
+			      NULL);
+		g_free (icon_name);
+		return;
 	}
 
-	return res;
-}
+	/* We'll have to compose the emblems onto the main icon */
 
-static void
-add_new_printer_icon (GnomePrinterList *list)
-{
-	EggIconListItem *item;
-	GdkPixbuf *pixbuf = load_icon (GTK_WIDGET (list), "gnome-dev-printer-new");
-	if (pixbuf == NULL)
-		pixbuf = load_icon (GTK_WIDGET (list), GTK_STOCK_PRINT);
+	widget = GTK_WIDGET (cell_layout);
+	gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
+					   GTK_ICON_SIZE_DIALOG,
+					   &width, &height);
 
-	item = egg_icon_list_item_new (pixbuf, _("New Printer"));
-	list->details->add_item = item;
+	icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
 
-	g_object_unref (pixbuf);
+	pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name, width, 0, NULL);
+	g_free (icon_name);
 
-	egg_icon_list_append_item (EGG_ICON_LIST (list), item);
-}
+	/* FIXME: is this fallback really necessary? */
+	if (!pixbuf) {
+		pixbuf = gtk_widget_render_icon (widget,
+						 GTK_STOCK_PRINT,
+						 GTK_ICON_SIZE_DIALOG,
+						 NULL);
+	}
 
-static GdkPixbuf *
-get_printer_icon (GtkWidget *list, GnomeCupsPrinter *printer)
-{
-	char *icon_name;
-	GList *ptr, *emblems;
-	GdkPixbuf *pixbuf, *emblem;
-	GError *err = NULL;
+	for (ptr = emblems; ptr != NULL; ptr = ptr->next) {
+		const char *emblem_name = (const char *) ptr->data;
+		GdkPixbuf *emblem, *copy;
 
-	gnome_cups_printer_get_icon (printer,
-				     &icon_name,
-				     &emblems);
-	pixbuf = load_icon (GTK_WIDGET (list), icon_name);
-	g_free (icon_name);
-	if (pixbuf == NULL)
-		pixbuf = load_icon (GTK_WIDGET (list), GTK_STOCK_PRINT);
+		/* FIXME: can that really happen? Not according to the gnome_cups_printer_get_icon code in libgnomecups! */
+		if (!emblem_name)
+			continue;
 
-	for (ptr = emblems; ptr != NULL; ptr = ptr->next) {
-		if (ptr->data == NULL)
+		emblem = gtk_icon_theme_load_icon (icon_theme, emblem_name,
+						   width, 0, NULL);
+		if (!emblem)
 			continue;
-		emblem = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-			ptr->data, 48, 0, &err);
-		if (emblem == NULL) {
-			g_warning ("unable to load emblem '%s'", (char *)ptr->data);
-			if (err != NULL) {
-				g_warning ("%s", err->message);
-				g_error_free (err);
-				err = NULL;
-			}
-		} else {
-			GdkPixbuf *res = gdk_pixbuf_copy (pixbuf);
-			gdk_pixbuf_composite (emblem,  res, 0, 0, 
-				gdk_pixbuf_get_width (res), gdk_pixbuf_get_height (res), 
-				0., 0., 1., 1., GDK_INTERP_NEAREST, 255);
-			g_object_unref (pixbuf);
-			pixbuf = res;
-		}
+
+		copy = gdk_pixbuf_copy (pixbuf);
+
+		gdk_pixbuf_composite (emblem, copy,
+				      0, 0,
+				      gdk_pixbuf_get_width (copy),
+				      gdk_pixbuf_get_height (copy),
+				      0.0, 0.0, 1.0, 1.0,
+				      GDK_INTERP_NEAREST, 255);
+
+		g_object_unref (emblem);
+		g_object_unref (pixbuf);
+
+		pixbuf = copy;
+	}
+
+	g_list_foreach (emblems, (GFunc) g_free, NULL);
+	g_list_free (emblems);
+
+	g_object_set (cell,
+		      "icon-name", NULL,
+		      "pixbuf", pixbuf,
+		      NULL);
+	if (pixbuf) {
+		g_object_unref (pixbuf);
 	}
 
-	return pixbuf;
+	g_object_unref (printer);
 }
 
-static char *
-get_printer_label (GnomeCupsPrinter *printer)
+static void
+printer_get_text_func (GtkCellLayout *cell_layout,
+		       GtkCellRenderer *cell,
+		       GtkTreeModel *model,
+		       GtkTreeIter *iter,
+		       gpointer data)
 {
-	char const *name  = gnome_cups_printer_get_name (printer);
-	char const *state = gnome_cups_printer_get_state_name (printer);
-	int jobs = gnome_cups_printer_get_job_count (printer);
+	GnomeCupsPrinter *printer = NULL;
+	char *text;
+	char const *name, *state;
+	int jobs;
+
+	gtk_tree_model_get (model,
+			    iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	d(g_print ("Getting label for printer %s\n", printer ? gnome_cups_printer_get_name (printer) : "NEW-PRINTER"););
+
+	if (printer == NULL) {
+		g_object_set (cell,
+			      "text", _("New Printer"),
+			      NULL);
+		return;
+	}
+
+	name = gnome_cups_printer_get_name (printer);
+	state = gnome_cups_printer_get_state_name (printer);
+	jobs = gnome_cups_printer_get_job_count (printer);
 
 	/* FIXME: hard-coded additional text color */
 	if (jobs > 0) {
-		return g_strdup_printf ("%s\n<span color=\"#337F33\">%s\n%d Jobs</span>",
-			name, state, jobs);
+		char *jobs_text;
+
+		jobs_text = g_strdup_printf (ngettext ("%d Job", "%d Jobs", jobs), jobs);
+		text = g_strdup_printf ("%s\n<span color=\"#337F33\">%s\n%s</span>",
+					name, state, jobs_text);
+		g_free (jobs_text);
 	} else {
-		return g_strdup_printf ("%s\n<span color=\"#33337F\">%s\n</span>",
-			name, state);
+		text = g_strdup_printf ("%s\n<span color=\"#33337F\">%s\n</span>",
+					name, state);
 	}
+
+	g_object_set (cell,
+		      "markup", text,
+		      NULL);
+	g_free (text);
+
+	g_object_unref (printer);
 }
 
-static EggIconListItem *
-create_printer_item (GtkWidget *list, GnomeCupsPrinter *printer)
+static void
+printer_activated_cb (GtkIconView *icon_view,
+		      GtkTreePath *path,
+		      GnomePrinterList *list)
 {
-	EggIconListItem *item;
-	GdkPixbuf *pixbuf;
-	char *label;
-	
-	pixbuf = get_printer_icon (list, printer);
-	label = get_printer_label (printer);
-	
-	item = egg_icon_list_item_new (pixbuf, label);
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
 
-	egg_icon_list_item_set_data (item, printer);
-
-	g_object_unref (pixbuf);
-	g_free (label);
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
 
-	return item;
-}
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
 
-static void
-printer_activated_cb (GnomePrinterList *list,
-		      GnomeCupsPrinter *printer)
-{	
-	gnome_cups_manager_view_queue (printer);
+	if (printer == NULL) {
+		gnome_printer_list_new_printer (list);
+	} else {
+		gnome_cups_manager_view_queue (printer);
+		g_object_unref (printer);
+	}
 }
 
 static void
-item_activated_cb (GnomePrinterList *list,
-		   EggIconListItem *item,
-		   gpointer user_data)
+printer_pause_cb (GtkIconView *icon_view,
+		  GtkTreePath *path,
+		  GnomePrinterList *list)
 {
-	gnome_printer_list_selection_activate (list);
-}
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
+	GError *error = NULL;
 
-static void
-open_activated_cb (GtkWidget *item,
-		   gpointer user_data)
-{
-	gnome_printer_list_selection_activate (GNOME_PRINTER_LIST (user_data));
-}
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
 
-static void
-pause_activated_cb (GtkWidget *item,
-		    gpointer user_data)
-{
-	gnome_printer_list_selection_pause (GNOME_PRINTER_LIST (user_data));
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return;
+
+	gnome_cups_printer_pause (printer, &error);
+	if (error) {
+		char *msg;
+		/* FIXME i18n! */
+		msg = g_strdup_printf ("Could not pause '%s'",
+				       gnome_cups_printer_get_name (printer));
+		gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
+		g_free (msg);
+		g_error_free (error);
+	}
+
+	g_object_unref (printer);
 }
 
 static void
-resume_activated_cb (GtkWidget *item,
-		     gpointer user_data)
+printer_resume_cb (GtkIconView *icon_view,
+		  GtkTreePath *path,
+		  GnomePrinterList *list)
 {
-	gnome_printer_list_selection_resume (GNOME_PRINTER_LIST (user_data));
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
+	GError *error = NULL;
+
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
+
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return;
+
+	gnome_cups_printer_resume (printer, &error);
+	if (error) {
+		char *msg;
+		/* FIXME i18n! */
+		msg = g_strdup_printf ("Could not resume '%s'",
+				       gnome_cups_printer_get_name (printer));
+		gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
+		g_free (msg);
+		g_error_free (error);
+	}
+
+	g_object_unref (printer);
 }
 
 static void
-make_default_activated_cb (GtkWidget *menu_item,
-			   gpointer user_data)
+printer_set_default_cb (GtkIconView *icon_view,
+			GtkTreePath *path,
+			GnomePrinterList *list)
 {
-	gnome_printer_list_selection_make_default (GNOME_PRINTER_LIST (user_data));
-}
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
+	GError *error = NULL;
+
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
+
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return;
+
+        gnome_cups_printer_set_default (printer, &error);
+	if (error) {
+		char *msg;
+		/* FIXME i18n! */
+                msg = g_strdup_printf ("Could not make '%s' the default printer", 
+                                       gnome_cups_printer_get_name (printer));
+		gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
+		g_free (msg);
+		g_error_free (error);
+	}
 
+	g_object_unref (printer);
+}
+	
 static void
-delete_activated_cb (GtkWidget *menu_item,
-		     gpointer user_data)
+printer_properties_cb (GtkIconView *icon_view,
+		       GtkTreePath *path,
+		       GnomePrinterList *list)
 {
-	gnome_printer_list_selection_delete (GNOME_PRINTER_LIST (user_data));
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
+
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
+
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return;
+
+	gnome_cups_manager_printer_properties (printer);
+
+	g_object_unref (printer);
 }
 
 static void
-properties_activated_cb (GtkWidget *menu_item,
-			 gpointer user_data)
+printer_remove_cb (GtkIconView *icon_view,
+		   GtkTreePath *path,
+		   GnomePrinterList *list)
 {
-	gnome_printer_list_selection_properties (GNOME_PRINTER_LIST (user_data));
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
+	GError *error = NULL;
+
+	/* |path| is a path in the icon view's model */
+	if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+		return;
+
+	gtk_tree_model_get (details->sort_model,
+			    &iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return;
+
+	gnome_cups_printer_delete (printer, &error);
+	if (error) {
+		char *msg;
+		/* FIXME: i18n! */
+		msg = g_strdup_printf ("Could not delete '%s'",
+					gnome_cups_printer_get_name (printer));
+		gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
+		g_free (msg);
+		g_error_free (error);
+	}
 }
 
 /* This is so lame */
-void
-gnome_printer_list_get_command_sensitivities (GnomePrinterList *list,
-					      gboolean *activate,
-					      gboolean *pause,
-					      gboolean *resume,
-					      gboolean *make_default,
-					      gboolean *del,
-					      gboolean *properties,
-					      gboolean *status)
-{
+static void
+get_command_sensitivities (GnomePrinterList *list,
+			   gboolean *activate,
+			   gboolean *pause,
+			   gboolean *resume,
+			   gboolean *make_default,
+			   gboolean *del,
+			   gboolean *properties,
+			   gboolean *status,
+			   gboolean *new_selected)
+{
+	GnomePrinterListDetails *details = list->details;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer = NULL;
 	GList *l;
 	GList *selection;
 	int num_selected;
@@ -255,7 +443,7 @@ gnome_printer_list_get_command_sensitivi
 	gboolean has_default;
 	gboolean all_running;
 
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
+	selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (list));
 	
 	num_selected = g_list_length (selection);
 
@@ -291,16 +479,20 @@ gnome_printer_list_get_command_sensitivi
 	has_default = FALSE;
 
 	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item;
-		
-		item = l->data;
-		
-		if (item == list->details->add_item) {
+		GtkTreePath *path = (GtkTreePath *) l->data;
+
+		/* |path| is a path in the icon view's model */
+		if (!gtk_tree_model_get_iter (details->sort_model, &iter, path))
+			return;
+
+		gtk_tree_model_get (details->sort_model,
+				    &iter,
+				    (int) 0, &printer,
+				    (int) -1);
+
+		if (printer == NULL) {
 			new_printer_selected = TRUE;
 		} else {
-			GnomeCupsPrinter *printer;
-
-			printer = GNOME_CUPS_PRINTER (egg_icon_list_item_get_data (item));
 			if (gnome_cups_printer_get_state (printer) == IPP_PRINTER_STOPPED) {
 				all_running = FALSE;
 			} else {
@@ -310,6 +502,8 @@ gnome_printer_list_get_command_sensitivi
 			if (gnome_cups_printer_get_is_default (printer)) {
 				has_default = TRUE;
 			}
+
+			g_object_unref (printer);
 		}
 	}
 	
@@ -341,15 +535,35 @@ gnome_printer_list_get_command_sensitivi
 		*status = !new_printer_selected;
 	}
 
+	if (new_selected) {
+		*new_selected = num_selected == 1 && new_printer_selected;
+	}
+
+	g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL);
 	g_list_free (selection);
 }
 
+/* This is so lame */
+void
+gnome_printer_list_get_command_sensitivities (GnomePrinterList *list,
+					      gboolean *activate,
+					      gboolean *pause,
+					      gboolean *resume,
+					      gboolean *make_default,
+					      gboolean *del,
+					      gboolean *properties,
+					      gboolean *status)
+{
+	get_command_sensitivities (list, activate, pause, resume,
+				  make_default, del, properties,
+				  status, NULL);
+}
+
 static GtkWidget *
 create_selection_menu (GnomePrinterList *list)
 {
 	GtkWidget *menu;
 	GtkWidget *item;
-	GList *selection;
 	gboolean activate;
 	gboolean pause;
 	gboolean resume;
@@ -357,35 +571,30 @@ create_selection_menu (GnomePrinterList 
 	gboolean del;
 	gboolean properties;
 	gboolean status;
+	gboolean new_selected;
 
-	gnome_printer_list_get_command_sensitivities (list,
+	get_command_sensitivities (list,
 		&activate, &pause, &resume, &make_default,
-		&del, &properties, &status);
+		&del, &properties, &status, &new_selected);
 	
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
 	menu = gtk_menu_new ();
-	gtk_widget_show (menu);
-
-	if (g_list_length (selection) == 1 && selection->data == list->details->add_item) {
-		g_list_free (selection);
 
+	if (new_selected) {
 		item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ADD, NULL);
 		gtk_widget_show (item);
-		g_signal_connect (item, "activate", 
-				  G_CALLBACK (open_activated_cb),
-				  list);
+		g_signal_connect_swapped (item, "activate", 
+				  	  G_CALLBACK (gnome_printer_list_selection_activate),
+					  list);
 		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 		return menu;
 	}
-	g_list_free (selection);
 
 	item = gtk_menu_item_new_with_label (_("Jobs"));
 	gtk_widget_show (item);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (open_activated_cb),
-			  list);
+	g_signal_connect_swapped (item, "activate",
+				  G_CALLBACK (gnome_printer_list_selection_activate),
+				  list);
 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 	item = gtk_separator_menu_item_new ();
@@ -395,26 +604,26 @@ create_selection_menu (GnomePrinterList 
 	item = gtk_menu_item_new_with_label (_("Pause"));
 	gtk_widget_show (item);
 	gtk_widget_set_sensitive (item, pause);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (pause_activated_cb),
-			  list);
+	g_signal_connect_swapped (item, "activate", 
+				  G_CALLBACK (gnome_printer_list_selection_pause),
+				  list);
 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 	item = gtk_menu_item_new_with_label (_("Resume"));
 	gtk_widget_show (item);
 	gtk_widget_set_sensitive (item, resume);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (resume_activated_cb),
-			  list);
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);	
+	g_signal_connect_swapped (item, "activate", 
+				  G_CALLBACK (gnome_printer_list_selection_resume),
+				  list);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 	item = gtk_menu_item_new_with_label (_("Make Default"));
 	gtk_widget_show (item);
 	gtk_widget_set_sensitive (item, make_default);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (make_default_activated_cb),
-			  list);
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);	
+	g_signal_connect_swapped (item, "activate", 
+				  G_CALLBACK (gnome_printer_list_selection_make_default),
+				  list);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 	item = gtk_separator_menu_item_new ();
 	gtk_widget_show (item);
@@ -423,9 +632,9 @@ create_selection_menu (GnomePrinterList 
 	item = gtk_image_menu_item_new_from_stock (GTK_STOCK_REMOVE, NULL);
 	gtk_widget_show (item);
 	gtk_widget_set_sensitive (item, del);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (delete_activated_cb),
-			  list);
+	g_signal_connect_swapped (item, "activate", 
+				  G_CALLBACK (gnome_printer_list_selection_delete),
+				  list);
 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
 	item = gtk_separator_menu_item_new ();
@@ -435,179 +644,101 @@ create_selection_menu (GnomePrinterList 
 	item = gtk_image_menu_item_new_from_stock (GTK_STOCK_PROPERTIES, NULL);
 	gtk_widget_show (item);
 	gtk_widget_set_sensitive (item, properties);
-	g_signal_connect (item, "activate", 
-			  G_CALLBACK (properties_activated_cb),
-			  list);
+	g_signal_connect_swapped (item, "activate", 
+				  G_CALLBACK (gnome_printer_list_selection_properties),
+				  list);
 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 	
 	return menu;
 }
 
-static void
-context_menu_popup (GnomePrinterList *list,
-		    GdkEventButton *event)
+static gboolean
+button_press_cb (GnomePrinterList *list,
+		 GdkEventButton *event,
+		 gpointer data)
 {
+	GtkIconView *icon_view;
+	GtkTreePath *path;
 	GtkWidget *menu;
-	
-	menu = create_selection_menu (list);
 
-	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
-}
+	if (event->button != 3 ||
+	    event->type != GDK_BUTTON_PRESS)
+		return FALSE;
 
-static gboolean
-button_press_event_cb (GnomePrinterList *list,
-		       GdkEventButton *event,
-		       gpointer user_data)
-{
-	if (event->button == 3) {
-		EggIconListItem *item;
-		
-		item = egg_icon_list_get_item_at_pos (EGG_ICON_LIST (list), 
-						      event->x, event->y);
-		if (!item) {
-			return FALSE;
-		}
+	icon_view = GTK_ICON_VIEW (list);
+	path = gtk_icon_view_get_path_at_pos (icon_view, event->x, event->y);
+	if (!path)
+		return FALSE;
 
-		if (!egg_icon_list_item_is_selected (item)) {
-			egg_icon_list_unselect_all (EGG_ICON_LIST (list));
-			egg_icon_list_select_item (EGG_ICON_LIST (list),
-						   item);
-		}
-		
-		context_menu_popup (list, event);
-		
-		return TRUE;
+	if (!gtk_icon_view_path_is_selected (icon_view, path)) {
+		gtk_icon_view_unselect_all (icon_view);
+		gtk_icon_view_select_path (icon_view, path);
 	}
 
-	return FALSE;
-}
-
-static void
-printer_changed_cb (GnomeCupsPrinter *printer,
-		    GnomePrinterList *list)
-{
-	EggIconListItem *item;
-	GdkPixbuf *pixbuf;
-	char *label;
-
-	d (g_warning ("changed %s", gnome_cups_printer_get_name (printer)););
-
-	item = g_object_get_data (G_OBJECT (printer), "icon_item");
-	
-	pixbuf = get_printer_icon (GTK_WIDGET (list), printer);
-	label = get_printer_label (printer);
-	
-	egg_icon_list_item_set_icon (item, pixbuf);
-	egg_icon_list_item_set_label (item, label);
-
-	g_signal_emit_by_name (list, "selection_changed");
-
-	g_object_unref (pixbuf);
-	g_free (label);
-}
-
-static void
-printer_gone_cb (GnomeCupsPrinter *printer,
-		 gpointer user_data)
-{
-	GnomePrinterList *list;
-	EggIconListItem *item;
-
-	d (g_warning ("removed %s", gnome_cups_printer_get_name (printer)););
-
-	list = GNOME_PRINTER_LIST (user_data);
-	item = g_object_get_data (G_OBJECT (printer), "icon_item");
-
-	egg_icon_list_remove_item (EGG_ICON_LIST (list), item);
-	
-	list->details->printers = g_list_remove (list->details->printers, printer);
-
-	disconnect_printer (list, printer);
-}
-
-static void
-disconnect_printer (GnomePrinterList *list,
-                    GnomeCupsPrinter *printer)
-{
-        g_signal_handlers_disconnect_by_func (printer,
-                                              G_CALLBACK (printer_changed_cb),
-                                              printer);
-        g_signal_handlers_disconnect_by_func (printer,
-                                              G_CALLBACK (printer_gone_cb),
-                                              printer);
-        g_object_unref (printer);
-}
-
-static void
-watch_printer (GnomePrinterList *list,
-	       const char *printer_name)
-{
-	EggIconListItem *item;
-	GnomeCupsPrinter *printer = gnome_cups_printer_get (printer_name);
-
-	if (!printer)
-		return;
-
-	list->details->printers = g_list_append (list->details->printers, 
-						 printer);
-	g_object_ref (printer);
-	
-	item = create_printer_item (GTK_WIDGET (list), printer);
-	g_object_set_data_full (G_OBJECT (printer), "icon_item", item,
-		(GDestroyNotify)egg_icon_list_item_unref);
-
-	egg_icon_list_append_item (EGG_ICON_LIST (list), item);
+	gtk_tree_path_free (path);
 
-	g_signal_connect_object (printer, "is_default_changed",
-				 G_CALLBACK (printer_changed_cb),
-				 list, 0);
-	g_signal_connect_object (printer, "attributes_changed",
-				 G_CALLBACK (printer_changed_cb),
-				 list, 0);
-	g_signal_connect_object (printer, "gone",
-				 G_CALLBACK (printer_gone_cb),
-				 list, 0);
-	printer_changed_cb (printer, list);
-}
+	menu = create_selection_menu (list);
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+			NULL, NULL,
+			event->button, event->time);
 
-static void
-printer_added_cb (const char *name, gpointer user_data)
-{
-	GnomePrinterList *list;
-	
-	list = GNOME_PRINTER_LIST (user_data);
-	
-	d (g_warning ("added %s", name););
-	watch_printer (list, name);
+	return TRUE;
 }
 
-static int
-icon_compare (EggIconList *icon_list,
-	      EggIconListItem *a,
-	      EggIconListItem *b,
-	      gpointer user_data)
+static gboolean
+popup_menu_cb (GnomePrinterList *list,
+	       gpointer data)
 {
-	GnomePrinterList *list = GNOME_PRINTER_LIST (icon_list);
-	GnomeCupsPrinter *printer_a;
-	GnomeCupsPrinter *printer_b;
-	
-	if (a == b) {
-		return 0;
-	}
+	GtkWidget *menu;
 
-	if (a == list->details->add_item) {
-		return -1;
-	}
-	
-	if (b == list->details->add_item) {
-		return 1;
+	menu = create_selection_menu (list);
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+			/* FIXME: GtkIconView should provide a position_menu function!! */
+			NULL, NULL,
+			0, gtk_get_current_event_time ());
+
+	return TRUE;
+}
+
+static gint
+printer_compare_func (GtkTreeModel *model,
+		      GtkTreeIter *iter_a,
+		      GtkTreeIter *iter_b,
+		      gpointer data)
+{
+	GnomeCupsPrinter *printer_a = NULL, *printer_b = NULL;
+	gint retval;
+
+	gtk_tree_model_get (model,
+			    iter_a,
+			    (int) 0, &printer_a,
+			    (int) -1);
+	gtk_tree_model_get (model,
+			    iter_b,
+			    (int) 0, &printer_b,
+			    (int) -1);
+
+	if (printer_a != NULL && printer_b != NULL) {
+		const char *name_a, *name_b;
+
+		name_a = gnome_cups_printer_get_name (printer_a);
+		name_b = gnome_cups_printer_get_name (printer_b);
+
+		retval = g_utf8_collate (name_a, name_b);
+
+		g_object_unref (printer_a);
+		g_object_unref (printer_b);
+	} else if (printer_a != NULL) {
+		retval = 1;
+		g_object_unref (printer_a);
+	} else if (printer_b != NULL) {
+		retval = -1;
+		g_object_unref (printer_b);
+	} else {
+		retval = 0;
 	}
-
-	printer_a = egg_icon_list_item_get_data (a);
-	printer_b = egg_icon_list_item_get_data (b);
-
-	return strcmp (gnome_cups_printer_get_name (printer_a),
-		       gnome_cups_printer_get_name (printer_b));
+		
+	return retval;
 }
 
 void
@@ -622,176 +753,52 @@ gnome_printer_list_new_printer (GnomePri
 void
 gnome_printer_list_selection_activate (GnomePrinterList *list)
 {
-	GList *selection;
-	GList *l;
-	
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
-	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item = l->data;
-
-		if (item == list->details->add_item) {
-			gnome_printer_list_new_printer (list);
-		} else {
-			GnomeCupsPrinter *printer;
-			
-			printer = egg_icon_list_item_get_data (item);
-			printer_activated_cb (list, printer);
-		}
-	}
-
-	g_list_free (selection);
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_activated_cb,
+					list);
 }
 
 void
 gnome_printer_list_selection_pause (GnomePrinterList *list)
 {
-	GList *selection;
-	GList *l;
-	
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
-	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item = l->data;
-
-		if (item != list->details->add_item) {
-			GnomeCupsPrinter *printer;
-			GError *error = NULL;
-			
-			printer = egg_icon_list_item_get_data (item);
-
-			gnome_cups_printer_pause (printer, &error);
-			if (error) {
-				char *msg;
-				msg = g_strdup_printf ("Could not pause '%s'", 
-						       gnome_cups_printer_get_name (printer));
-				gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
-				g_free (msg);
-				g_error_free (error);
-			}
-		}
-	}
-
-	g_list_free (selection);
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_pause_cb,
+					list);
 }
 
 void
 gnome_printer_list_selection_resume (GnomePrinterList *list)
 {
-	GList *selection;
-	GList *l;
-	
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
-	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item = l->data;
-
-		if (item != list->details->add_item) {
-			GnomeCupsPrinter *printer;
-			GError *error = NULL;
-			
-			printer = egg_icon_list_item_get_data (item);
-
-			gnome_cups_printer_resume (printer, &error);
-			if (error) {
-				char *msg;
-				msg = g_strdup_printf ("Could not resume '%s'", 
-						       gnome_cups_printer_get_name (printer));
-				gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
-				g_free (msg);
-				g_error_free (error);
-			}
-		}
-	}
-
-	g_list_free (selection);
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_resume_cb,
+					list);
 }
 
 void
 gnome_printer_list_selection_make_default (GnomePrinterList *list)
 {
-	
-	GList *selection;
-	GnomeCupsPrinter *printer;
-	EggIconListItem *item;
-	GError *error = NULL;
-
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-        g_return_if_fail (g_list_length (selection) == 1);
-
-	item = selection->data;
-        g_return_if_fail (item != list->details->add_item);
-
-	printer = GNOME_CUPS_PRINTER (egg_icon_list_item_get_data (item));
-        gnome_cups_printer_set_default (printer, &error);
-        if (error) {
-                char *msg;
-                msg = g_strdup_printf ("Could not make '%s' the default printer", 
-                                       gnome_cups_printer_get_name (printer));
-				gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
-                g_free (msg);
-                g_error_free (error);
-        }
-
-	g_list_free (selection);
+	/* We will in fact have only one selected item here, but this is more convenient */
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_set_default_cb,
+					list);
 }
 
 void
 gnome_printer_list_selection_properties (GnomePrinterList *list)
 {
-	GList *selection;
-	GList *l;
-	
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
-	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item = l->data;
-
-		if (item != list->details->add_item) {
-			GnomeCupsPrinter *printer;
-			
-			printer = egg_icon_list_item_get_data (item);
-
-			gnome_cups_manager_printer_properties (printer);
-		}
-	}
-
-	g_list_free (selection);
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_properties_cb,
+					list);
 }
 
 void
 gnome_printer_list_selection_delete (GnomePrinterList *list)
 {
-	GList *selection;
-	GList *l;
-
-	selection = egg_icon_list_get_selected (EGG_ICON_LIST (list));
-
-	for (l = selection; l != NULL; l = l->next) {
-		EggIconListItem *item = l->data;
-
-		if (item != list->details->add_item) {
-			GnomeCupsPrinter *printer;
-			GError *error = NULL;
-			
-			printer = egg_icon_list_item_get_data (item);
-
-			gnome_cups_printer_delete (printer, &error);
-			if (error) {
-				char *msg;
-				msg = g_strdup_printf ("Could not delete '%s'", 
-						       gnome_cups_printer_get_name (printer));
-				gnome_cups_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (list))), msg, error);
-				g_free (msg);
-				g_error_free (error);
-			}
-		}
-	}
-
-	g_list_free (selection);
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (list),
+					(GtkIconViewForeachFunc) printer_remove_cb,
+					list);
 }
 
-
 static void
 gnome_printer_list_init (GnomePrinterList *list)
 {
@@ -795,76 +802,110 @@ gnome_printer_list_selection_delete (Gno
 static void
 gnome_printer_list_init (GnomePrinterList *list)
 {
-	GList *printer_names;
-	GList *l;
-	
-	list->details = g_new0 (GnomePrinterListDetails, 1);
-
+	list->details = G_TYPE_INSTANCE_GET_PRIVATE (list, GNOME_TYPE_PRINTER_LIST, GnomePrinterListDetails);
+}
 
-	egg_icon_list_set_sort_func (EGG_ICON_LIST (list),
-				     icon_compare,
-				     list,
-				     NULL);
-	egg_icon_list_set_sorted (EGG_ICON_LIST (list), TRUE);
+static GObject *
+gnome_printer_list_constructor (GType type,
+	                        guint n_construct_properties,
+        	                GObjectConstructParam *construct_params)
 
-	add_new_printer_icon (list);
+{
+	GObject *object;
+	GtkIconView *icon_view;
+	GtkCellLayout *cell_layout;
+	GnomePrinterList *list;
+	GnomePrinterListDetails *details;
+	GtkCellRenderer *renderer;
 	
-	printer_names = gnome_cups_get_printers ();
-	for (l = printer_names; l != NULL; l = l->next) {
-		watch_printer (list, l->data);
-	}
-	gnome_cups_printer_list_free (printer_names);
+        object = G_OBJECT_CLASS (gnome_printer_list_parent_class)->constructor
+			(type, n_construct_properties, construct_params);
 
-	list->details->new_printer_notify = 
-		gnome_cups_printer_new_printer_notify_add (printer_added_cb,
-							   list);
+	icon_view = GTK_ICON_VIEW (object);
+	cell_layout = GTK_CELL_LAYOUT (icon_view);
+	list = GNOME_PRINTER_LIST (icon_view);
+	details = list->details;
+
+	g_signal_connect (list, "button-press-event",
+			  G_CALLBACK (button_press_cb), NULL);
+	g_signal_connect (list, "popup-menu",
+			  G_CALLBACK (popup_menu_cb), NULL);
+	g_signal_connect (list, "item-activated",
+			  G_CALLBACK (printer_activated_cb), list);
+
+
+	details->printers_model = gnome_printers_model_new ();
+	details->tree_model = gnome_printers_model_get_tree_model (details->printers_model);
+
+	details->sort_model = gtk_tree_model_sort_new_with_model (details->tree_model);
+
+	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (details->sort_model),
+						 printer_compare_func,
+						 NULL, NULL);
+
+	gtk_icon_view_set_model (icon_view, details->sort_model);
+	g_object_unref (details->sort_model);
+
+	gtk_icon_view_set_selection_mode (icon_view, GTK_SELECTION_MULTIPLE);
+
+	/* Cell renderers */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	gtk_cell_layout_pack_start (cell_layout, renderer, FALSE);
+	g_object_set (renderer,
+		      "follow-state", (gboolean) TRUE,
+		      "stock-size", (glong) GTK_ICON_SIZE_DIALOG,
+		      NULL);
+	gtk_cell_layout_set_cell_data_func (cell_layout,
+					    renderer,
+					    printer_get_pixbuf_func,
+					    list, NULL);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_end (cell_layout, renderer, FALSE);
+	g_object_set (renderer,
+		      "editable", FALSE,
+		      "xalign", 0.5,
+		      "wrap-mode", PANGO_WRAP_WORD_CHAR,
+		      "wrap-width", 100,
+		      NULL);
+	gtk_cell_layout_set_cell_data_func (cell_layout,
+					    renderer,
+					    printer_get_text_func,
+					    list, NULL);
 
-	egg_icon_list_set_selection_mode (EGG_ICON_LIST (list),
-					  GTK_SELECTION_MULTIPLE);
-
-	g_signal_connect (list, "item_activated", 
-			  G_CALLBACK (item_activated_cb), NULL);
-
-	g_signal_connect (list, "button_press_event",
-			  G_CALLBACK (button_press_event_cb), NULL);
+	return object;
 }
 
 static void
 gnome_printer_list_destroy (GtkObject *object)
 {
-	GnomePrinterList *list;
-	GList *l;
+	GnomePrinterList *list = GNOME_PRINTER_LIST (object);
+	GnomePrinterListDetails *details = list->details;
 
-	list = GNOME_PRINTER_LIST (object);
+	if (details->printers_model) {
+		gtk_icon_view_set_model (GTK_ICON_VIEW (list), NULL);
 
-	for (l = list->details->printers; l != NULL; l = l->next) {
-		disconnect_printer (list, GNOME_CUPS_PRINTER (l->data));
-	}
+		g_object_unref (details->printers_model);
+		details->printers_model = NULL;
 
-	g_list_free (list->details->printers);
-	list->details->printers = NULL;
-	
-	if (list->details->new_printer_notify) {
-		gnome_cups_printer_new_printer_notify_remove (list->details->new_printer_notify);
-		list->details->new_printer_notify = 0;
+		details->tree_model = NULL;
+		details->sort_model = NULL;
 	}
-	
-        GTK_OBJECT_CLASS (gnome_printer_list_parent_class)-> destroy, (object);
+
+        GTK_OBJECT_CLASS (gnome_printer_list_parent_class)->destroy (object);
 }
 
 static void
-gnome_printer_list_finalize (GObject *object)
+gnome_printer_list_class_init (GnomePrinterListClass *klass)
 {
-	GnomePrinterList *list = GNOME_PRINTER_LIST (object);
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass);
 
-	g_free (list->details);
-}
+	gobject_class->constructor = gnome_printer_list_constructor;
 
-static void
-gnome_printer_list_class_init (GnomePrinterListClass *class)
-{
-	GTK_OBJECT_CLASS (class)->destroy = gnome_printer_list_destroy;
-	G_OBJECT_CLASS (class)->finalize = gnome_printer_list_finalize;
+	gtkobject_class->destroy = gnome_printer_list_destroy;
+
+	g_type_class_add_private (gobject_class, sizeof (GnomePrinterListDetails));
 }
 
 GtkWidget *
Index: gnome-cups-manager/gnome-printer-list.h
===================================================================
RCS file: /cvs/gnome/gnome-cups-manager/gnome-cups-manager/gnome-printer-list.h,v
retrieving revision 1.2
diff -p -u -B -r1.2 gnome-printer-list.h
--- gnome-cups-manager/gnome-printer-list.h	13 Sep 2004 20:04:13 -0000	1.2
+++ gnome-cups-manager/gnome-printer-list.h	14 Dec 2006 14:58:21 -0000
@@ -1,10 +1,7 @@
 #ifndef GNOME_PRINTER_LIST_H
 #define GNOME_PRINTER_LIST_H
 
-#include <glib.h>
-#include <glib-object.h>
-
-#include "eggiconlist.h"
+#include <gtk/gtkiconview.h>
 
 G_BEGIN_DECLS
 
@@ -20,13 +17,13 @@ typedef struct _GnomePrinterListClass   
 typedef struct _GnomePrinterListDetails GnomePrinterListDetails;
 
 struct _GnomePrinterList {
-	EggIconList parent;
+	GtkIconView parent;
 	
 	GnomePrinterListDetails *details;
 };
 
 struct _GnomePrinterListClass {
-	EggIconListClass parent_class;
+	GtkIconViewClass parent_class;
 };
 
 GType      gnome_printer_list_get_type                  (void);
Index: gnome-cups-manager/gnome-printers-model.c
===================================================================
RCS file: gnome-cups-manager/gnome-printers-model.c
diff -N gnome-cups-manager/gnome-printers-model.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnome-cups-manager/gnome-printers-model.c	14 Dec 2006 14:58:21 -0000
@@ -0,0 +1,316 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * gnome-printer-list.c
+ * Copyright (C) 2003-2004, Ximian, Inc.
+ * Copyright (C) 2006 Christian Persch
+ *
+ * Authors:
+ *   Dave Camp <dave@ximian.com>
+ *   Jody Goldberg <jody@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Library General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This file 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
+ * Library General Public License for more priv.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this file; if not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include <config.h>
+
+#include "gnome-printers-model.h"
+
+#include <gtk/gtkliststore.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreesortable.h>
+#include <gtk/gtktreemodelsort.h>
+
+#include <libgnomecups/gnome-cups-printer.h>
+#include <libgnomecups/gnome-cups-ui-util.h>
+#include <libgnomecups/gnome-cups-permission.h>
+
+struct _GnomePrintersModelPrivate {
+	GtkListStore *store;
+	GtkTreeModel *model;
+
+	guint printer_added_id;
+	guint printer_removed_id;
+};
+
+/* Tool to help debug lifecycle */
+#if 1
+#define d(code)	do { code } while (0)
+#else
+#define d(code)
+#endif
+
+#define TREE_PATH_DATA_KEY	"Printer::TreePath"
+
+G_DEFINE_TYPE (GnomePrintersModel, gnome_printers_model, G_TYPE_OBJECT);
+
+static void printer_changed_cb (GnomeCupsPrinter *printer, GnomePrintersModel *model);
+static void printer_gone_cb    (GnomeCupsPrinter *printer, GnomePrintersModel *model);
+
+static void
+disconnect_printer (GnomePrintersModel *model,
+                    GnomeCupsPrinter *printer)
+{
+        g_signal_handlers_disconnect_by_func (printer,
+                                              G_CALLBACK (printer_changed_cb),
+                                              model);
+        g_signal_handlers_disconnect_by_func (printer,
+                                              G_CALLBACK (printer_gone_cb),
+                                              model);
+}
+
+static void
+gnome_printers_model_add_printer (GnomePrintersModel *model,
+				  const char *printer_name)
+{
+	GnomePrintersModelPrivate *priv = model->priv;
+	GtkTreeIter iter;
+	GnomeCupsPrinter *printer;
+
+	printer = gnome_cups_printer_get (printer_name);
+
+	if (!printer)
+		return;
+
+	g_signal_connect_object (printer, "is-default-changed",
+				 G_CALLBACK (printer_changed_cb),
+				 model, 0);
+	g_signal_connect_object (printer, "attributes-changed",
+				 G_CALLBACK (printer_changed_cb),
+				 model, 0);
+	g_signal_connect_object (printer, "gone",
+				 G_CALLBACK (printer_gone_cb),
+				 model, 0);
+
+	gtk_list_store_insert_with_values (priv->store,
+					   &iter,
+					   -1 /* position */,
+					   (int) 0, printer,
+					   (int) -1);
+
+	g_object_set_data_full (G_OBJECT (printer),
+				TREE_PATH_DATA_KEY,
+				gtk_tree_model_get_path (priv->model, &iter),
+				(GDestroyNotify) gtk_tree_path_free);
+
+	g_object_unref (printer);
+}
+
+static void
+gnome_printers_model_remove_printer (GnomePrintersModel *model,
+				     GnomeCupsPrinter *printer)
+{
+	GnomePrintersModelPrivate *priv = model->priv;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	d (g_print ("removed %s\n", gnome_cups_printer_get_name (printer)););
+
+	if (!printer)
+		return;
+
+	disconnect_printer (model, printer);
+
+	path = g_object_steal_data (G_OBJECT (printer), TREE_PATH_DATA_KEY);
+	if (!path) {
+		d (g_print ("Printer not in model!?\n"););
+		return;
+	}
+
+	if (!gtk_tree_model_get_iter (priv->model, &iter, path)) {
+		d (g_print ("Cannot convert path to iter!?\n"););
+		return;
+	}
+
+	gtk_list_store_remove (priv->store, &iter);
+
+	gtk_tree_path_free (path);
+}
+
+static void
+printer_changed_cb (GnomeCupsPrinter *printer,
+		    GnomePrintersModel *model)
+{
+	GnomePrintersModelPrivate *priv = model->priv;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	d (g_print ("Changed %s\n", gnome_cups_printer_get_name (printer)););
+
+	path = g_object_get_data (G_OBJECT (printer), TREE_PATH_DATA_KEY);
+	if (!path) {
+		d (g_print ("Printer not in model!?\n"););
+		return;
+	}
+
+	if (!gtk_tree_model_get_iter (priv->model, &iter, path)) {
+		d (g_print ("Cannot convert path to iter!?\n"););
+		return;
+	}
+
+	gtk_tree_model_row_changed (priv->model, path, &iter);
+}
+
+static void
+printer_gone_cb (GnomeCupsPrinter *printer,
+		 GnomePrintersModel *model)
+{
+	d (g_print ("removed %s\n", gnome_cups_printer_get_name (printer)););
+
+	gnome_printers_model_remove_printer (model, printer);
+}
+
+static void
+printer_added_cb (const char *name,
+		  gpointer data)
+{
+	GnomePrintersModel *model = GNOME_PRINTERS_MODEL (data);
+
+	d (g_print ("added %s\n", name););
+
+	gnome_printers_model_add_printer (model, name);
+}
+
+static void
+printer_removed_cb (const char *printer_name,
+		    gpointer data)
+{
+	GnomePrintersModel *model = GNOME_PRINTERS_MODEL (data);
+	GnomeCupsPrinter *printer;
+
+	d (g_print ("removed %s\n", printer_name););
+
+	printer = gnome_cups_printer_get (printer_name);
+	if (!printer)
+		return;
+
+	gnome_printers_model_remove_printer (model, printer);
+
+	g_object_unref (printer);
+}
+
+static void
+gnome_printers_model_init (GnomePrintersModel *model)
+{
+	GnomePrintersModelPrivate *priv;
+	GtkTreeIter iter;
+	GList *l, *printer_names;
+
+	priv = model->priv = G_TYPE_INSTANCE_GET_PRIVATE (model, GNOME_TYPE_PRINTERS_MODEL, GnomePrintersModelPrivate);
+
+	/* The store owns one reference to each printer */
+	priv->store = gtk_list_store_new (1, GNOME_CUPS_TYPE_PRINTER);
+	g_assert (gtk_tree_model_get_flags (GTK_TREE_MODEL (priv->store)) & GTK_TREE_MODEL_ITERS_PERSIST);
+
+	priv->model = GTK_TREE_MODEL (priv->store);
+
+	/* Add NULL row which represents the "New Printer" icon */
+	gtk_list_store_insert_with_values (priv->store,
+					   &iter,
+					   (int) 0 /* position */,
+					   (int) 0, NULL,
+					   (int) -1);
+	
+	/* Now add the printers */
+	printer_names = gnome_cups_get_printers ();
+	for (l = printer_names; l != NULL; l = l->next) {
+		gnome_printers_model_add_printer (model, (const char *) l->data);
+	}
+	gnome_cups_printer_list_free (printer_names);
+
+	/* Listen for changes */
+	priv->printer_added_id =
+		gnome_cups_printer_new_printer_notify_add (printer_added_cb,
+							   model);
+	priv->printer_removed_id =
+		gnome_cups_printer_printer_removed_notify_add (printer_removed_cb,
+							       model);
+}
+
+static gboolean
+foreach_disconnect (GtkTreeModel *model,
+		    GtkTreePath *path,
+		    GtkTreeIter *iter,
+		    GnomePrintersModel *printers_model)
+{
+	GnomeCupsPrinter *printer = NULL;
+
+	gtk_tree_model_get (model,
+			    iter,
+			    (int) 0, &printer,
+			    (int) -1);
+
+	if (printer == NULL)
+		return FALSE;
+
+	disconnect_printer (printers_model, printer);
+
+	g_object_unref (printer);
+
+	/* continue */
+	return FALSE;
+}
+
+static void
+gnome_printers_model_dispose (GObject *object)
+{
+	GnomePrintersModel *model = GNOME_PRINTERS_MODEL (object);
+	GnomePrintersModelPrivate *priv = model->priv;
+
+	if (priv->model) {
+		g_object_ref (priv->model);
+		gtk_tree_model_foreach (priv->model,
+					(GtkTreeModelForeachFunc) foreach_disconnect,
+					model);
+		gtk_list_store_clear (priv->store);
+		g_object_unref (priv->model);
+		priv->store = NULL;
+		priv->model = NULL;
+	}
+
+	if (priv->printer_added_id != 0) {
+		gnome_cups_printer_new_printer_notify_remove (priv->printer_added_id);
+		priv->printer_added_id = 0;
+	}
+	if (priv->printer_removed_id != 0) {
+		gnome_cups_printer_printer_removed_notify_remove (priv->printer_removed_id);
+		priv->printer_removed_id = 0;
+	}
+
+        G_OBJECT_CLASS (gnome_printers_model_parent_class)->dispose (object);
+}
+
+static void
+gnome_printers_model_class_init (GnomePrintersModelClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->dispose = gnome_printers_model_dispose;
+
+	g_type_class_add_private (gobject_class, sizeof (GnomePrintersModelPrivate));
+}
+
+GnomePrintersModel *
+gnome_printers_model_new (void)
+{
+	return g_object_new (GNOME_TYPE_PRINTERS_MODEL, NULL);
+}
+
+GtkTreeModel *
+gnome_printers_model_get_tree_model (GnomePrintersModel *model)
+{
+	g_return_val_if_fail (GNOME_IS_PRINTERS_MODEL (model), NULL);
+
+	return model->priv->model;
+}
Index: gnome-cups-manager/gnome-printers-model.h
===================================================================
RCS file: gnome-cups-manager/gnome-printers-model.h
diff -N gnome-cups-manager/gnome-printers-model.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnome-cups-manager/gnome-printers-model.h	14 Dec 2006 14:58:21 -0000
@@ -0,0 +1,35 @@
+#ifndef GNOME_PRINTERS_MODEL_H
+#define GNOME_PRINTERS_MODEL_H
+
+#include <gtk/gtkiconview.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_PRINTERS_MODEL            (gnome_printers_model_get_type())
+#define GNOME_PRINTERS_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_PRINTERS_MODEL, GnomePrintersModel))
+#define GNOME_PRINTERS_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_PRINTERS_MODEL, GnomePrintersModelClass))
+#define GNOME_IS_PRINTERS_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_PRINTERS_MODEL))
+#define GNOME_IS_PRINTERS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GNOME_TYPE_PRINTERS_MODEL))
+#define GNOME_PRINTERS_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GNOME_TYPE_PRINTERS_MODEL, GnomePrintersModelClass))
+
+typedef struct _GnomePrintersModel        GnomePrintersModel;
+typedef struct _GnomePrintersModelClass   GnomePrintersModelClass;
+typedef struct _GnomePrintersModelPrivate GnomePrintersModelPrivate;
+
+struct _GnomePrintersModel {
+	GObject parent;
+	
+	GnomePrintersModelPrivate *priv;
+};
+
+struct _GnomePrintersModelClass {
+	GObjectClass parent_class;
+};
+
+GType		 	gnome_printers_model_get_type		(void);
+GnomePrintersModel     *gnome_printers_model_new		(void);
+GtkTreeModel	       *gnome_printers_model_get_tree_model	(GnomePrintersModel *model);
+
+G_END_DECLS
+	
+#endif
Index: gnome-cups-manager/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-cups-manager/gnome-cups-manager/Makefile.am,v
retrieving revision 1.16
diff -p -u -B -r1.16 Makefile.am
--- gnome-cups-manager/Makefile.am	27 Sep 2004 19:41:14 -0000	1.16
+++ gnome-cups-manager/Makefile.am	14 Dec 2006 14:58:21 -0000
@@ -15,36 +15,15 @@ cupsmanagerdata_DATA=gnome-cups-manager.
 
 bin_PROGRAMS = gnome-cups-icon gnome-cups-manager
 
-eggmarshalers.h : eggmarshalers.list $(GLIB_GENMARSHAL)
-	$(GLIB_GENMARSHAL) $< --header --prefix=_egg_marshal > $@
-eggmarshalers.c : eggmarshalers.list $(GLIB_GENMARSHAL)
-	$(GLIB_GENMARSHAL) $< --body --prefix=_egg_marshal > $@.tmp
-	echo '/* This file has been automatically generated.  Do not edit.  */' >$@
-	echo '#include "'$*.h'"' >>$@
-	cat $@.tmp >>$@
-	rm -f $@.tmp
-
-BUILT_SOURCES =			\
-	eggmarshalers.h		\
-	eggmarshalers.c
-
-cut_and_paste_sources =		\
-	$(BUILT_SOURCES)	\
-	eggtrayicon.c		\
-	eggtrayicon.h
-
 gnome_cups_icon_SOURCES= \
-	$(cut_and_paste_sources) \
 	gnome-cups-icon.c \
 	tray.c \
 	tray.h
 
 gnome_cups_manager_SOURCES =	\
-	$(BUILT_SOURCES)	\
-	eggiconlist.c		\
-	eggiconlist.h		\
-	eggintl.h \
 	gnome-cups-manager.c \
+	gnome-printers-model.c \
+	gnome-printers-model.h \
 	gnome-printer-list.c \
 	gnome-printer-list.h \
 	printer-properties.c \
@@ -71,5 +50,4 @@ gnomecupsmanagerdir=$(datadir)/gnome-cup
 gnomecupsmanager_DATA=xd2-testpage-letter.eps xd2-testpage-a4.eps
 
 DISTCLEANFILES=$(server_DATA)
-EXTRA_DIST=gnome-cups-manager.glade $(server_in_files) $(gnomecupsmanager_DATA) \
-	eggmarshalers.list
+EXTRA_DIST=gnome-cups-manager.glade $(server_in_files) $(gnomecupsmanager_DATA)
Index: gnome-cups-manager/view-printers.c
===================================================================
RCS file: /cvs/gnome/gnome-cups-manager/gnome-cups-manager/view-printers.c,v
retrieving revision 1.9
diff -p -u -B -r1.9 view-printers.c
--- gnome-cups-manager/view-printers.c	1 Oct 2004 19:10:03 -0000	1.9
+++ gnome-cups-manager/view-printers.c	14 Dec 2006 14:58:21 -0000
@@ -247,7 +247,7 @@ update_menus (GladeXML *xml)
 }
 
 static void
-selection_changed_cb (EggIconList *list,
+selection_changed_cb (GnomePrinterList *list,
 		      gpointer user_data)
 {
 	update_menus (GLADE_XML (user_data));
