Index: configure.in
===================================================================
--- configure.in.orig
+++ configure.in
@@ -37,7 +37,7 @@ LIBXML_REQUIRED=2.0
 RSVG_REQUIRED=2.12
 DBUS_REQUIRED=0.7
 
-PKG_CHECK_MODULES(PROCMAN, glib-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED libgtop-2.0 >= $LIBGTOP_REQUIRED libwnck-1.0 >= $LIBWNCK_REQUIRED gtk+-2.0 >= $GTK_REQUIRED gnome-icon-theme >= $GNOME_ICON_THEME_REQUIRED gtkmm-2.4 >= $GTKMM_REQUIRED libxml-2.0 >= $LIBXML_REQUIRED librsvg-2.0 >= $RSVG_REQUIRED glibmm-2.4 >= $GLIBMM_REQUIRED giomm-2.4 >= $GIOMM_REQUIRED dbus-glib-1 >= $DBUS_REQUIRED)
+PKG_CHECK_MODULES(PROCMAN, glib-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED libgtop-2.0 >= $LIBGTOP_REQUIRED libwnck-1.0 >= $LIBWNCK_REQUIRED gtk+-2.0 >= $GTK_REQUIRED gnome-icon-theme >= $GNOME_ICON_THEME_REQUIRED gtkmm-2.4 >= $GTKMM_REQUIRED libxml-2.0 >= $LIBXML_REQUIRED librsvg-2.0 >= $RSVG_REQUIRED glibmm-2.4 >= $GLIBMM_REQUIRED giomm-2.4 >= $GIOMM_REQUIRED dbus-glib-1 >= $DBUS_REQUIRED hal hwinfo)
 
 
 AC_ARG_ENABLE(more-warnings,
Index: src/hardware.h
===================================================================
--- /dev/null
+++ src/hardware.h
@@ -0,0 +1,32 @@
+/* Gnome System Monitor - hardware.h
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * 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 Library 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 _GSM_HARDWARE_H_
+#define _GSM_HARDWARE_H_
+
+#include <gtk/gtkwidget.h>
+
+
+GtkWidget* create_hardware_view();
+
+
+#endif
Index: src/hardware.cpp
===================================================================
--- /dev/null
+++ src/hardware.cpp
@@ -0,0 +1,293 @@
+/* Gnome System Monitor - hardware.cpp
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * 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 Library 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 <glib/gi18n.h>
+
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkscrolledwindow.h>
+
+#include <sigc++/bind.h>
+#include <gtkmm/treeiter.h>
+
+#include <hd.h>
+
+#include "hardware.h"
+#include "interface.h"
+
+enum HwColumns
+{
+	HW_DEVICE,
+	HW_TYPE,
+	HW_ICON,
+	HW_N_COLUMNS
+};
+
+
+struct hw_map_data_t {
+	hd_hw_item_t key;
+	const char * icon;
+	const char * type_label;
+};
+
+typedef std::map<hd_hw_item_t, const hw_map_data_t*> hw_map_t;
+
+static const hw_map_t & get_map_data()
+{
+	static hw_map_t s_map;
+	static const hw_map_data_t _s_map_data[] = {
+		{ hw_sys, "system", "" },
+		{ hw_cpu, "", _("CPU") },
+		{ hw_keyboard, "keyboard", _("Keyboard") },
+		{ hw_braille, "braille", _("Braille device") },
+		{ hw_mouse, "mouse", _("Mouse") },
+		{ hw_joystick, "joystick", _("Joystick") },
+		{ hw_printer, "printer", _("Printer") },
+		{ hw_scanner, "scanner", _("Scanner") },
+		{ hw_chipcard, "", "chipcard??" },
+		{ hw_monitor, "display", _("Monitor") },
+		{ hw_tv, "", _("TV") },
+		{ hw_framebuffer, "", _("Framebuffer") },
+		{ hw_camera, "camera", _("Camera") },
+		{ hw_sound, "audio-card", _("Sound card") },
+		{ hw_storage_ctrl, "", _("Storage controller") },
+		{ hw_network_ctrl, "", _("Network controller") },
+		{ hw_isdn, "", _("ISDN adapter") },
+		{ hw_modem, "modem", _("Modem") },
+		{ hw_network, "network-wired", _("Network interface") },
+		{ hw_disk, "drive-harddisk", _("Hard drive") },
+		{ hw_partition, "", _("Partition") },
+		{ hw_cdrom, "drive-cdrom", _("CDROM Drive") },
+		{ hw_floppy, "media-floppy", _("Floppy Drive") },
+		{ hw_manual, "", "manual???" },
+		{ hw_usb_ctrl, "", _("USB Controller") },
+		{ hw_usb, "", _("USB Device") },
+		{ hw_bios, "", _("BIOS") },
+		{ hw_pci, "", _("PCI Device") },
+		{ hw_isapnp, "", _("ISA PnP Device") },
+		{ hw_bridge, "", _("Bridge") },
+		{ hw_hub, "", _("Hub") },
+		{ hw_scsi, "", _("SCSI Device") },
+		{ hw_ide, "", _("IDE Device") },
+		{ hw_memory, "", _("Memory") },
+		{ hw_dvb, "", _("DV-B Receiver") },
+		{ hw_pcmcia, "", _("PCMCIA Card") },
+		{ hw_pcmcia_ctrl, "", _("PCMCIA Controller") },
+		{ hw_ieee1394, "", _("Firewire Device") },
+		{ hw_ieee1394_ctrl, "", _("Firewire Controller") },
+		{ hw_hotplug, "", _("Hotplug Device") },
+		{ hw_hotplug_ctrl, "", _("Hotplug Controller") },
+		{ hw_zip, "media-zip", _("Zip Drive") },
+		{ hw_pppoe, "", _("PPPoE Interface") },
+		{ hw_wlan, "", _("WLAN Interface") },
+		{ hw_redasd, "", "redasd??" },
+		{ hw_dsl, "", _("DSL Modem") },
+		{ hw_block, "", _("Block Device") },
+		{ hw_tape, "media-tape", _("Tape Drive") },
+		{ hw_vbe, "", _("vbe???") },
+		{ hw_bluetooth, "", _("Bluetooth Device") },
+		{ hw_fingerprint, "", _("Fingerprint Reader") },
+
+		{ hw_none, NULL, NULL }
+	};
+	if (s_map.empty()) {
+		const struct hw_map_data_t *p = _s_map_data;
+		while ((p->key != hw_none) &&  (p->key != hw_bridge)) {
+			s_map.insert(std::make_pair(p->key, p));
+			p++;
+		}
+	}
+	return s_map;
+}
+
+static
+const char * get_hardware_type(hd_hw_item_t hwclass)
+{
+	const hw_map_t & hw_map(get_map_data());
+
+	hw_map_t::const_iterator iter = hw_map.find(hwclass);
+	if(iter != hw_map.end() && iter->second) {
+		return iter->second->type_label;
+	}
+	return NULL;
+}
+
+
+static
+Glib::RefPtr<Gdk::Pixbuf> get_hardware_icon(hd_hw_item_t hwclass)
+{
+	Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+
+	Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
+
+	const hw_map_t & hw_map(get_map_data());
+
+	hw_map_t::const_iterator iter = hw_map.find(hwclass);
+	if(iter != hw_map.end() && iter->second && iter->second->icon
+		&& *iter->second->icon) {
+		pixbuf = icon_theme->load_icon(iter->second->icon, 16,
+									   Gtk::ICON_LOOKUP_USE_BUILTIN);
+	}
+
+	return pixbuf;
+}
+
+static
+void populate_hardware_view(GtkTreeStore * model)
+{
+	hd_data_t *hd_data;
+	hd_t *hd;
+
+	g_object_freeze_notify(G_OBJECT(model));
+
+	std::map<std::string, Gtk::TreeIter> item_map;
+	std::list<Gtk::TreeIter> unparented;
+	hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
+
+	hd = hd_list(hd_data, hw_all, 1, NULL);
+	for(; hd; hd = hd->next) {
+		const char * name = hd->model;
+		hd_hw_item_t iclass = hd->hw_class;
+		// for now skip network interfaces.
+		if(iclass == hw_network)
+			continue;
+		GtkTreeIter *parent = NULL;
+		if(hd->parent_id) {
+			std::map<std::string, Gtk::TreeIter>::iterator iter;
+			iter = item_map.find(hd->parent_id);
+			if(iter != item_map.end()) {
+				parent = iter->second.gobj();
+			}
+		}
+
+		Glib::RefPtr<Gdk::Pixbuf> pixbuf = get_hardware_icon(iclass);
+		const char * device_type = get_hardware_type(iclass);
+		if(name && *name) {
+			Gtk::TreeIter iter;
+			gtk_tree_store_append(model, iter.gobj(), parent);
+			gtk_tree_store_set(model, iter.gobj(), HW_DEVICE, name,
+							   HW_ICON, pixbuf ? pixbuf->gobj() : NULL,
+							   HW_TYPE, device_type ? device_type : "",
+							   -1);
+			item_map[hd->unique_id] = iter;
+			if(hd->parent_id && !parent) {
+				// has a parent id but no parent found
+				unparented.push_front(iter);
+			}
+		}
+	}
+
+	while(!unparented.empty()) {
+		Gtk::TreeIter treeiter(unparented.front());
+
+		printf("TODO reparent\n");
+		// reparent
+		unparented.pop_front();
+	}
+
+
+	hd_free_hd_list(hd);          /* free it */
+	hd_free_hd_data(hd_data);
+	free(hd_data);
+	free(hd);
+	g_object_thaw_notify(G_OBJECT(model));
+	g_object_unref(model);
+}
+
+
+
+GtkWidget* create_hardware_view()
+{
+	GtkWidget *vbox;
+	GtkWidget *label;
+	GtkWidget *scrolled;
+	GtkWidget *hw_tree;
+	GtkTreeStore *model;
+	GtkTreeViewColumn *col;
+	GtkCellRenderer *cell;
+
+	const gchar * const titles[] = {
+		N_("Device"),
+		N_("Type")
+	};
+
+	vbox = gtk_vbox_new (FALSE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+	label = make_title_label(_("Hardware"));
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+
+	scrolled = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
+				       GTK_POLICY_AUTOMATIC,
+				       GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
+					    GTK_SHADOW_IN);
+
+	gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
+
+	model = gtk_tree_store_new(HW_N_COLUMNS,	/* n columns */
+							   G_TYPE_STRING,	/* HW_DEVICE */
+							   G_TYPE_STRING,   /* HW_TYPE */
+							   GDK_TYPE_PIXBUF	/* HW_ICON */
+		);
+
+	hw_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
+	gtk_container_add(GTK_CONTAINER(scrolled), hw_tree);
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(hw_tree), TRUE);
+	g_object_unref(G_OBJECT(model));
+
+	/* icon + device */
+
+	col = gtk_tree_view_column_new();
+	cell = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(col, cell, FALSE);
+	gtk_tree_view_column_set_attributes(col, cell, "pixbuf", HW_ICON,
+					    NULL);
+	cell = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(col, cell, FALSE);
+	gtk_tree_view_column_set_attributes(col, cell, "text", HW_DEVICE,
+					    NULL);
+	gtk_tree_view_column_set_title(col, titles[HW_DEVICE]);
+	gtk_tree_view_column_set_sort_column_id(col, HW_DEVICE);
+	gtk_tree_view_column_set_reorderable(col, TRUE);
+	gtk_tree_view_column_set_resizable(col, TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(hw_tree), col);
+
+	/* type */
+	col = gtk_tree_view_column_new();
+	cell = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(col, cell, FALSE);
+	gtk_tree_view_column_set_attributes(col, cell, "text", HW_TYPE,
+										NULL);
+	gtk_tree_view_column_set_title(col, titles[HW_TYPE]);
+	gtk_tree_view_column_set_sort_column_id(col, HW_TYPE);
+	gtk_tree_view_column_set_reorderable(col, TRUE);
+	gtk_tree_view_column_set_resizable(col, TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(hw_tree), col);
+
+	if(!Glib::thread_supported())
+		Glib::thread_init();
+	Glib::Thread::create(sigc::bind(&populate_hardware_view, GTK_TREE_STORE(g_object_ref(model))), false);
+
+	gtk_widget_show_all(vbox);
+
+	return vbox;
+}
+
+
Index: src/interface.cpp
===================================================================
--- src/interface.cpp.orig
+++ src/interface.cpp
@@ -1,5 +1,6 @@
 /* Procman - main window
  * Copyright (C) 2001 Kevin Vandersloot
+ * Copyright (C) 2008 Novell, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -40,6 +41,7 @@
 #include "disks.h"
 #include "sysinfo.h"
 #include "gsm_color_button.h"
+#include "hardware.h"
 
 static void	cb_toggle_tree (GtkAction *action, gpointer data);
 
@@ -610,9 +612,9 @@ create_main_window (ProcData *procdata)
 	GtkWidget *menubar;
 	GtkWidget *main_box;
 	GtkWidget *notebook;
-	GtkWidget *tab_label1, *tab_label2, *tab_label3;
+	GtkWidget *tab_label1, *tab_label2, *tab_label3 , *tab_label4;
 	GtkWidget *vbox1;
-	GtkWidget *sys_box, *devices_box;
+	GtkWidget *sys_box, *devices_box, *hardware_box;
 	GtkWidget *sysinfo_box, *sysinfo_label;
 
 	app = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -702,6 +704,10 @@ create_main_window (ProcData *procdata)
 	tab_label3 = gtk_label_new (_("File Systems"));
 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), devices_box, tab_label3);
 
+	hardware_box = create_hardware_view ();
+	tab_label4 = gtk_label_new (_("Hardware"));
+	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), hardware_box, tab_label4);
+
 	g_signal_connect (G_OBJECT (notebook), "switch-page",
 			  G_CALLBACK (cb_switch_page), procdata);
 	g_signal_connect (G_OBJECT (notebook), "change-current-page",
Index: src/Makefile.am
===================================================================
--- src/Makefile.am.orig
+++ src/Makefile.am
@@ -24,6 +24,7 @@ gnome_system_monitor_SOURCES = \
 	smooth_refresh.cpp smooth_refresh.h \
 	defaulttable.h \
 	disks.cpp disks.h \
+	hardware.cpp hardware.h  \
 	selinux.h selinux.cpp \
 	procman_gnomesu.h procman_gnomesu.cpp \
 	procman_gksu.h procman_gksu.cpp \
Index: src/sysinfo.cpp
===================================================================
--- src/sysinfo.cpp.orig
+++ src/sysinfo.cpp
@@ -13,6 +13,8 @@
 #include <glibtop/mem.h>
 #include <glibtop/sysinfo.h>
 
+#include <libhal.h>
+
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/socket.h>
@@ -36,6 +38,18 @@ using std::vector;
 
 namespace {
 
+  string get_hal_property(LibHalContext * ctx, const char *udi, const char *prop_name,
+                          DBusError * error)
+  {
+    string prop_val;
+    char * property;
+    property = libhal_device_get_property_string(ctx, udi, prop_name, error);
+    if(property) {
+      prop_val = property;
+      libhal_free_string(property);
+    }
+    return prop_val;
+  }
 
   class SysInfo
   {
@@ -51,6 +65,12 @@ namespace {
     guint n_processors;
     vector<string> processors;
 
+    /* system info */
+    string bios_version;
+    string bios_date;
+    string machine_type_model;
+    string system_serial;
+    string system_board_serial;
 
     SysInfo()
     {
@@ -59,6 +79,7 @@ namespace {
       this->load_disk_info();
       this->load_uname_info();
       this->load_gnome_version();
+      this->load_system_info();
     }
 
     virtual ~SysInfo()
@@ -182,6 +203,49 @@ namespace {
 
       this->gnome_version = values[0] + '.' + values[1] + '.' + values[2];
     }
+
+    void load_system_info()
+    {
+      //
+      DBusError error;
+      DBusConnection *connection;
+
+      dbus_error_init (&error);
+      connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+
+      LibHalContext * ctx = libhal_ctx_new();
+
+      if(ctx) {
+        libhal_ctx_set_dbus_connection (ctx, connection);
+        if(!libhal_ctx_init (ctx, &error)) {
+          printf("ctx init failed\n");
+          if (dbus_error_is_set (&error)) {
+            dbus_error_free (&error);
+            return;
+          }
+        }
+
+        this->bios_version = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+                                              "system.firmware.version", NULL);
+        this->bios_date = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+                                           "system.firmware.release_date", NULL);
+        this->machine_type_model = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+                                                    "system.product", NULL);
+        if(this->machine_type_model.empty()) {
+          dbus_error_init(&error);
+          this->machine_type_model = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+								"system.hardware.product", NULL);
+        }
+        this->system_serial = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+                                               "system.hardware.serial", NULL);
+        this->system_board_serial = get_hal_property(ctx, "/org/freedesktop/Hal/devices/computer",
+                                                     "system.hardware.uuid", NULL);
+
+        libhal_ctx_shutdown (ctx, &error);
+        libhal_ctx_free(ctx);
+      }
+      dbus_error_free(&error);
+    }
   };
 
 
@@ -485,6 +549,10 @@ procman_create_sysinfo_view(void)
   GtkWidget *memory_label;
   GtkWidget *processor_label;
 
+  GtkWidget *bios_table;
+  GtkWidget *bios_version_label;
+  GtkWidget *bios_date_label;
+
   GtkWidget *disk_space_table;
   GtkWidget *disk_space_label;
 
@@ -571,17 +639,20 @@ procman_create_sysinfo_view(void)
 
   /* hardware section */
 
-  markup = g_strdup_printf(_("<b>Hardware</b>"));
-  hardware_table = add_section(GTK_BOX(vbox), markup, data->processors.size(), 2, NULL);
-  g_free(markup);
+  hardware_table = add_section(GTK_BOX(vbox), _("<b>Hardware</b>"),
+							   data->processors.size() + 4, 2, NULL);
+
+  add_row(GTK_TABLE(hardware_table), _("Machine model:"),
+		  data->machine_type_model.c_str(), 0);
 
   markup = procman::format_size(data->memory_bytes);
   memory_label = add_row(GTK_TABLE(hardware_table), _("Memory:"),
-                         markup, 0);
+                         markup, 1);
   g_free(markup);
   header = gtk_label_new(_("Memory:"));
 
-  for (guint i = 0; i < data->processors.size(); ++i) {
+  guint i;
+  for (i = 0; i < data->processors.size(); ++i) {
     const gchar * t;
     if (data->processors.size() > 1) {
       markup = g_strdup_printf(_("Processor %d:"), i);
@@ -593,20 +664,33 @@ procman_create_sysinfo_view(void)
     }
 
     processor_label = add_row(GTK_TABLE(hardware_table), t,
-                              data->processors[i].c_str(), 1 + i);
+                              data->processors[i].c_str(), 2 + i);
 
     if(markup)
       g_free(markup);
   }
 
-  /* disk space section */
 
-  markup = g_strdup_printf(_("<b>System Status</b>"));
-  disk_space_table = add_section(GTK_BOX(vbox), markup, 1, 2, NULL);
-  g_free(markup);
+  add_row(GTK_TABLE(hardware_table), _("Serial number:"),
+		  data->system_serial.c_str(), 2 + i);
+  add_row(GTK_TABLE(hardware_table), _("System UUID:"),
+          data->system_board_serial.c_str(), 3 + i);
+
+  /* bios section */
+
+  bios_table = add_section(GTK_BOX(vbox), _("<b>BIOS</b>"), 2, 2, NULL);
+
+  bios_version_label = add_row(GTK_TABLE(bios_table), _("BIOS version:"),
+                               data->bios_version.c_str(), 0);
+  bios_date_label = add_row(GTK_TABLE(bios_table), _("BIOS date:"),
+                               data->bios_date.c_str(), 1);
+
+  /* disk space section */
+  disk_space_table = add_section(GTK_BOX(vbox), _("<b>System Status</b>"),
+								 1, 2, NULL);
 
   markup = procman::format_size(data->free_space_bytes);
-  disk_space_label = add_row(GTK_TABLE(disk_space_table), 
+  disk_space_label = add_row(GTK_TABLE(disk_space_table),
                              _("Available disk space:"), markup,
                              0);
   g_free(markup);
