Yelp Lovin'



Attached is a patch I got from the venerable Chris Lahey.
It implements search using Beagle, printing, and some weird
collapsing TOC thing I haven't played with yet.

It's been sitting in my Inbox for over a week now.  You guys
should play with it, then get back to me with three seperate
patches that I can review individually.

If it happens REAL soon, one or more of these might have a
chance of making it in before feature freeze.

--
Shaun



? docbookx.dtd
? examples.html
? test-mozembed
? test-mozembed.cpp
? yelp-libxslt.patch
? yelp-updates.patch
? yelp.patch
? data/ui/yelp.gladep
? src/yelp-toc.c
? src/yelp-toc.h
Index: configure.in
===================================================================
RCS file: /cvs/gnome/yelp/configure.in,v
retrieving revision 1.183
diff -u -p -r1.183 configure.in
--- configure.in	16 May 2005 21:02:32 -0000	1.183
+++ configure.in	6 Jul 2005 19:30:56 -0000
@@ -63,6 +63,8 @@ PKG_CHECK_MODULES(YELP,
 	libxml-2.0 >= 2.6.5
 	libxslt >= 1.1.4
 	libexslt >= 0.8.1
+	libgnome-menu >= 2.11.1
+	libbeagle-0.0 >= 0.2
 ])
 AC_SUBST([YELP_CFLAGS])
 AC_SUBST([YELP_LIBS])
Index: data/yelp.js
===================================================================
RCS file: /cvs/gnome/yelp/data/yelp.js,v
retrieving revision 1.2
diff -u -p -r1.2 yelp.js
--- data/yelp.js	9 May 2005 23:40:59 -0000	1.2
+++ data/yelp.js	6 Jul 2005 19:30:56 -0000
@@ -87,3 +87,72 @@ window.addEventListener("load",slt.init,
 window.addEventListener("DOMContentLoaded",slt.init,false);
 window.addEventListener("resize",slt.init,false);
 
+function createCookie(name,value,days)
+{
+	if (days)
+	{
+		var date = new Date();
+		date.setTime(date.getTime()+(days*24*60*60*1000));
+		var expires = "; expires="+date.toGMTString();
+	}
+	else var expires = "";
+	document.cookie = name+"="+value+expires+"; path=/";
+}
+
+function readCookie(name)
+{
+	var nameEQ = name + "=";
+	var ca = document.cookie.split(';');
+	for(var i=0;i < ca.length;i++)
+	{
+		var c = ca[i];
+		while (c.charAt(0)==' ') c = c.substring(1,c.length);
+		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
+	}
+	return null;
+}
+
+function eraseCookie(name)
+{
+	createCookie(name,"",-1);
+}
+
+function endsWith (haystack, needle)
+{
+    if (haystack.substring (haystack.length - needle.length, haystack.length) == needle) 
+	return true;
+    else
+	return false;
+}
+
+function load_hidden ()
+{
+    var ca = document.cookie.split(';');
+    for (var i=0; i < ca.length; i++) {
+	var c = ca[i];
+	while (c.charAt(0)==' ') c = c.substring(1,c.length);
+	if (c.indexOf('display:') == 0) {
+	    var colon = c.indexOf(':');
+	    var equal = c.indexOf('=');
+
+	    var id = c.substring (colon + 1, equal);
+	    var value = c.substring (equal + 1);
+
+	    document.getElementById (id).style.display = value;
+	}
+    }
+}
+
+function show_hide (id)
+{
+    var element = document.getElementById (id + '-children');
+    if (element.style.display == "none") {
+	element.style.display = "block";
+	createCookie ('display:' + id + '-children', "block", 1000);
+    } else {
+	element.style.display = "none";
+	createCookie ('display:' + id + '-children', "none", 1000);
+    }
+}
+
+window.addEventListener("DOMContentLoaded",load_hidden,false);
Index: data/ui/yelp-ui.xml
===================================================================
RCS file: /cvs/gnome/yelp/data/ui/yelp-ui.xml,v
retrieving revision 1.8
diff -u -p -r1.8 yelp-ui.xml
--- data/ui/yelp-ui.xml	2 Jan 2005 13:14:10 -0000	1.8
+++ data/ui/yelp-ui.xml	6 Jul 2005 19:30:56 -0000
@@ -6,6 +6,9 @@
       <separator/>
       <menuitem action="AboutDocument"/>
       <separator/>
+      <menuitem action="PrintPage"/>
+      <menuitem action="PrintDocument"/>
+      <separator/>
       <menuitem action="CloseWindow"/>
     </menu>
     <menu action="EditMenu">
@@ -42,6 +45,8 @@
     <toolitem action="GoForward"/>
     <separator/>
     <toolitem action="GoHome"/>
+    <separator/>
+    <toolitem action="Search"/>
   </toolbar>
   <popup>
     <menuitem action="OpenLink"/>
Index: data/ui/yelp.glade
===================================================================
RCS file: /cvs/gnome/yelp/data/ui/yelp.glade,v
retrieving revision 1.10
diff -u -p -r1.10 yelp.glade
--- data/ui/yelp.glade	21 Jan 2005 21:45:30 -0000	1.10
+++ data/ui/yelp.glade	6 Jul 2005 19:30:56 -0000
@@ -19,6 +19,7 @@
   <property name="skip_pager_hint">False</property>
   <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -102,6 +103,10 @@
 			  <property name="yalign">0.5</property>
 			  <property name="xpad">0</property>
 			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
 			</widget>
 			<packing>
 			  <property name="padding">0</property>
@@ -173,6 +178,10 @@
 			  <property name="yalign">0.5</property>
 			  <property name="xpad">0</property>
 			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
 			</widget>
 			<packing>
 			  <property name="padding">0</property>
@@ -200,7 +209,7 @@
 	  <property name="visible">True</property>
 	  <property name="xalign">0.5</property>
 	  <property name="yalign">1</property>
-	  <property name="xscale">0.9</property>
+	  <property name="xscale">0.899999976158</property>
 	  <property name="yscale">0.5</property>
 	  <property name="top_padding">0</property>
 	  <property name="bottom_padding">0</property>
@@ -233,6 +242,10 @@
 		      <property name="xpad">0</property>
 		      <property name="ypad">0</property>
 		      <property name="mnemonic_widget">find_entry</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
 		    </widget>
 		    <packing>
 		      <property name="padding">3</property>
@@ -340,6 +353,7 @@
   <property name="skip_pager_hint">False</property>
   <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -409,6 +423,10 @@
 	      <property name="xpad">0</property>
 	      <property name="ypad">0</property>
 	      <property name="mnemonic_widget">location_entry</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
 	    </widget>
 	    <packing>
 	      <property name="padding">0</property>
@@ -461,6 +479,7 @@
   <property name="skip_pager_hint">False</property>
   <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -521,6 +540,10 @@
 		  <property name="yalign">0.5</property>
 		  <property name="xpad">0</property>
 		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
 		</widget>
 		<packing>
 		  <property name="padding">0</property>
@@ -597,6 +620,10 @@
 			  <property name="xpad">0</property>
 			  <property name="ypad">0</property>
 			  <property name="mnemonic_widget">variable_font</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
 			</widget>
 			<packing>
 			  <property name="left_attach">0</property>
@@ -622,6 +649,10 @@
 			  <property name="xpad">0</property>
 			  <property name="ypad">0</property>
 			  <property name="mnemonic_widget">fixed_font</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
 			</widget>
 			<packing>
 			  <property name="left_attach">0</property>
@@ -706,6 +737,10 @@
 		  <property name="yalign">0.5</property>
 		  <property name="xpad">0</property>
 		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
 		</widget>
 		<packing>
 		  <property name="padding">0</property>
@@ -779,6 +814,7 @@
   <property name="skip_pager_hint">False</property>
   <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -837,6 +873,10 @@
 	      <property name="xpad">0</property>
 	      <property name="ypad">0</property>
 	      <property name="mnemonic_widget">bookmarks_view</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
 	    </widget>
 	    <packing>
 	      <property name="left_attach">0</property>
@@ -917,6 +957,9 @@
 		  <property name="rules_hint">False</property>
 		  <property name="reorderable">False</property>
 		  <property name="enable_search">True</property>
+		  <property name="fixed_height_mode">False</property>
+		  <property name="hover_selection">False</property>
+		  <property name="hover_expand">False</property>
 		</widget>
 	      </child>
 	    </widget>
@@ -952,6 +995,7 @@
   <property name="skip_pager_hint">False</property>
   <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -1033,6 +1077,10 @@
 		  <property name="xpad">0</property>
 		  <property name="ypad">0</property>
 		  <property name="mnemonic_widget">bookmark_title_entry</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
 		</widget>
 		<packing>
 		  <property name="padding">0</property>
@@ -1061,6 +1109,248 @@
 		</packing>
 	      </child>
 	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="print_dialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Print</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox10">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area10">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="button2">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="button3">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="has_focus">True</property>
+	      <property name="label">gtk-print</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">0</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkVBox" id="vbox135">
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">0</property>
+
+	  <child>
+	    <widget class="GtkRadioButton" id="radiobutton_page">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="active">True</property>
+	      <property name="inconsistent">False</property>
+	      <property name="draw_indicator">True</property>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment15">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">0</property>
+		  <property name="yscale">0</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">0</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox91">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">2</property>
+
+		      <child>
+			<widget class="GtkImage" id="image8">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-file</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label1232">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Print current pa_ge</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkRadioButton" id="radiobutton_document">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="active">False</property>
+	      <property name="inconsistent">False</property>
+	      <property name="draw_indicator">True</property>
+	      <property name="group">radiobutton_page</property>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment16">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">0</property>
+		  <property name="yscale">0</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">0</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox92">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">2</property>
+
+		      <child>
+			<widget class="GtkImage" id="image9">
+			  <property name="visible">True</property>
+			  <property name="stock">gnome-stock-book-blue</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label1233">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Print entire _document</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
 	  </child>
 	</widget>
 	<packing>
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/yelp/src/Makefile.am,v
retrieving revision 1.83
diff -u -p -r1.83 Makefile.am
--- src/Makefile.am	16 May 2005 21:02:33 -0000	1.83
+++ src/Makefile.am	6 Jul 2005 19:30:56 -0000
@@ -3,16 +3,20 @@ bin_PROGRAMS = yelp
 yelp_SOURCES =							\
 	$(gnome_yelp_idl_sources)				\
 	Yelper.cpp		Yelper.h			\
+	gtkentryaction.c	gtkentryaction.h		\
 	yelp-base.c		yelp-base.h			\
 	yelp-bookmarks.c 	yelp-bookmarks.h		\
 	yelp-cache.c		yelp-cache.h			\
 	yelp-db-pager.c		yelp-db-pager.h			\
+	yelp-db-print-pager.c	yelp-db-print-pager.h		\
 	yelp-error.c		yelp-error.h			\
 	yelp-gecko-utils.cpp	yelp-gecko-utils.h		\
 	yelp-html.cpp		yelp-html.h			\
 	yelp-io-channel.c	yelp-io-channel.h		\
 	yelp-pager.c		yelp-pager.h			\
+	yelp-search-pager.c	yelp-search-pager.h		\
 	yelp-settings.c		yelp-settings.h			\
+	yelp-toc.c		yelp-toc.h			\
 	yelp-toc-pager.c	yelp-toc-pager.h		\
 	yelp-utils.c		yelp-utils.h			\
 	yelp-window.c 		yelp-window.h			\
@@ -101,11 +105,13 @@ test_man_parser_LDADD = $(YELP_LIBS) $(Z
 
 test_pager_SOURCES =						\
 	yelp-db-pager.c		yelp-db-pager.h			\
+	yelp-db-print-pager.c	yelp-db-print-pager.h		\
 	yelp-error.c		yelp-error.h			\
 	yelp-io-channel.c	yelp-io-channel.h		\
 	yelp-man-pager.c	yelp-man-pager.h		\
 	yelp-man-parser.c	yelp-man-parser.h		\
 	yelp-pager.c		yelp-pager.h			\
+	yelp-search-pager.c	yelp-search-pager.h		\
 	yelp-toc-pager.c	yelp-toc-pager.h		\
 	yelp-utils.c		yelp-utils.h			\
 	yelp-xslt-pager.c	yelp-xslt-pager.h		\
Index: src/gtkentryaction.c
===================================================================
RCS file: src/gtkentryaction.c
diff -N src/gtkentryaction.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/gtkentryaction.c	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,306 @@
+/*
+ *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ *  Copyright (C) 2003, 2004 Christian Persch
+ *
+ *  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, 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.
+ *
+ *  $Id: ephy-location-action.c,v 1.36 2005/02/06 14:37:12 chpe Exp $
+ */
+
+#include "config.h"
+
+#include "gtkentryaction.h"
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtktoolitem.h>
+
+#define GTK_ENTRY_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_ENTRY_ACTION, GtkEntryActionPrivate))
+
+struct _GtkEntryActionPrivate
+{
+	char *text;
+	gboolean editable;
+};
+
+static void  gtk_entry_action_init        (GtkEntryAction      *action);
+static void  gtk_entry_action_class_init  (GtkEntryActionClass *class);
+static void  changed_cb                   (GtkEntry            *entry,
+					   GtkEntryAction      *action);
+static void  sync_text                    (GtkAction           *gaction,
+					   GParamSpec          *pspec,
+					   GtkWidget           *proxy);
+
+enum
+{
+	PROP_0,
+	PROP_TEXT,
+	PROP_EDITABLE,
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+gtk_entry_action_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0))
+    {
+      static const GTypeInfo type_info =
+	{
+	  sizeof (GtkEntryActionClass),
+	  (GBaseInitFunc) NULL,
+	  (GBaseFinalizeFunc) NULL,
+	  (GClassInitFunc) gtk_entry_action_class_init,
+	  (GClassFinalizeFunc) NULL,
+	  NULL,
+	  sizeof (GtkEntryAction),
+	  0, /* n_preallocs */
+	  (GInstanceInitFunc) gtk_entry_action_init,
+	};
+
+      type = g_type_register_static (GTK_TYPE_ACTION,
+				     "GtkEntryAction",
+				     &type_info, 0);
+    }
+
+  return type;
+}
+
+static GtkWidget *
+gtk_entry_action_create_tool_item (GtkAction *action)
+{
+  GtkToolItem *tool_item;
+  GtkWidget *entry;
+
+  tool_item = gtk_tool_item_new ();
+  entry = gtk_entry_new ();
+  gtk_container_add (GTK_CONTAINER (tool_item), entry);
+  gtk_widget_show (entry);
+
+  return GTK_WIDGET (tool_item);
+}
+
+static void
+sync_text (GtkAction *gaction,
+	   GParamSpec *pspec,
+	   GtkWidget *proxy)
+{
+  GtkEntryAction *action = GTK_ENTRY_ACTION (gaction);
+  GtkToolItem *item = GTK_TOOL_ITEM (proxy);
+  GtkEntry *entry = GTK_ENTRY (GTK_BIN (item)->child);
+
+  g_signal_handlers_block_by_func (entry, G_CALLBACK (changed_cb), action);
+  gtk_entry_set_text (entry, action->priv->text);
+  g_signal_handlers_unblock_by_func (entry, G_CALLBACK (changed_cb), action);
+}
+
+static void
+sync_editable (GtkAction *gaction,
+	       GParamSpec *pspec,
+	       GtkWidget *proxy)
+{
+  GtkEntryAction *action = GTK_ENTRY_ACTION (gaction);
+  GtkToolItem *item = GTK_TOOL_ITEM (proxy);
+  GtkEntry *entry = GTK_ENTRY (GTK_BIN (item)->child);
+
+  gtk_editable_set_editable (GTK_EDITABLE (entry), action->priv->editable);
+}
+
+static void
+changed_cb (GtkEntry *entry, GtkEntryAction *action)
+{
+  const char *text;
+  GtkWidget *proxy = GTK_WIDGET (entry)->parent;
+
+  text = gtk_entry_get_text (entry);
+
+  g_signal_handlers_block_by_func (action, G_CALLBACK (sync_text), proxy);
+  gtk_entry_action_set_text (action, text);
+  g_signal_handlers_unblock_by_func (action, G_CALLBACK (sync_text), proxy);
+}
+
+static void
+connect_proxy (GtkAction *action, GtkWidget *proxy)
+{
+  if (GTK_IS_TOOL_ITEM (proxy) && GTK_IS_ENTRY (GTK_BIN (proxy)->child))
+    {
+      GtkToolItem *item = GTK_TOOL_ITEM (proxy);
+      GtkEntry *entry = GTK_ENTRY (GTK_BIN (item)->child);
+
+      sync_text (action, NULL, proxy);
+      g_signal_connect_object (action, "notify::text",
+			       G_CALLBACK (sync_text), proxy, 0);
+      sync_editable (action, NULL, proxy);
+      g_signal_connect_object (action, "notify::editable",
+			       G_CALLBACK (sync_editable), proxy, 0);
+
+      g_signal_connect_object (entry, "activate",
+			       G_CALLBACK (gtk_action_activate), action,
+			       G_CONNECT_SWAPPED);
+      g_signal_connect_object (entry, "changed",
+			       G_CALLBACK (changed_cb), action, 0);
+    }
+
+  GTK_ACTION_CLASS (parent_class)->connect_proxy (action, proxy);
+}
+
+static void
+disconnect_proxy (GtkAction *action, GtkWidget *proxy)
+{
+  GTK_ACTION_CLASS (parent_class)->disconnect_proxy (action, proxy);
+
+  if (GTK_IS_TOOL_ITEM (proxy) && GTK_IS_ENTRY (GTK_BIN (proxy)->child))
+    {
+      GtkToolItem *item = GTK_TOOL_ITEM (proxy);
+      GtkEntry *entry = GTK_ENTRY (GTK_BIN (item)->child);
+
+      g_signal_handlers_disconnect_matched (action, G_SIGNAL_MATCH_DATA,
+					    0, 0, NULL, NULL, proxy);
+      g_signal_handlers_disconnect_matched (entry, G_SIGNAL_MATCH_DATA,
+					    0, 0, NULL, NULL, action);
+    }
+}
+
+static void
+gtk_entry_action_set_property (GObject *object,
+				   guint prop_id,
+				   const GValue *value,
+				   GParamSpec *pspec)
+{
+  GtkEntryAction *action = GTK_ENTRY_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      gtk_entry_action_set_text (action, g_value_get_string (value));
+      break;
+    case PROP_EDITABLE:
+      action->priv->editable = g_value_get_boolean (value);
+      break;
+    }
+}
+
+static void
+gtk_entry_action_get_property (GObject *object,
+				   guint prop_id,
+				   GValue *value,
+				   GParamSpec *pspec)
+{
+  GtkEntryAction *action = GTK_ENTRY_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      g_value_set_string (value, gtk_entry_action_get_text (action));
+      break;
+    case PROP_EDITABLE:
+      g_value_set_boolean (value, action->priv->editable);
+      break;
+    }
+}
+
+static void
+gtk_entry_action_finalize (GObject *object)
+{
+  GtkEntryAction *action = GTK_ENTRY_ACTION (object);
+  GtkEntryActionPrivate *priv = action->priv;
+
+  g_free (priv->text);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gtk_entry_action_class_init (GtkEntryActionClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkActionClass *action_class = GTK_ACTION_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+
+  object_class->finalize = gtk_entry_action_finalize;
+  object_class->get_property = gtk_entry_action_get_property;
+  object_class->set_property = gtk_entry_action_set_property;
+
+  action_class->create_tool_item = gtk_entry_action_create_tool_item;
+  action_class->connect_proxy = connect_proxy;
+  action_class->disconnect_proxy = disconnect_proxy;
+
+  g_object_class_install_property (object_class,
+				   PROP_TEXT,
+				   g_param_spec_string ("text",
+							"Text",
+							"The text",
+							"",
+							G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_EDITABLE,
+				   g_param_spec_boolean ("editable",
+							 "Editable",
+							 "Editable",
+							 TRUE,
+							 G_PARAM_READWRITE));
+
+  g_type_class_add_private (object_class, sizeof (GtkEntryActionPrivate));
+}
+
+static void
+gtk_entry_action_init (GtkEntryAction *action)
+{
+  action->priv = GTK_ENTRY_ACTION_GET_PRIVATE (action);
+
+  action->priv->text = g_strdup ("");
+  action->priv->editable = TRUE;
+}
+
+GtkAction *
+gtk_entry_action_new (const gchar *name,
+		      const gchar *label,
+		      const gchar *tooltip,
+		      const gchar *stock_id)
+{
+  GtkAction *action;
+
+  action = g_object_new (GTK_TYPE_ENTRY_ACTION,
+			 "name", name,
+			 "label", label,
+			 "tooltip", tooltip,
+			 "stock_id", stock_id,
+			 NULL);
+
+  return action;
+}
+
+const char *
+gtk_entry_action_get_text (GtkEntryAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ENTRY_ACTION (action), "");
+
+  return action->priv->text;
+}
+
+void
+gtk_entry_action_set_text (GtkEntryAction *action,
+			   const char *text)
+{
+  char *old_text;
+  g_return_if_fail (GTK_IS_ENTRY_ACTION (action));
+
+  old_text = action->priv->text;
+  action->priv->text = g_strdup (text);
+  g_free (old_text);
+  g_object_notify (G_OBJECT (action), "text");
+}
Index: src/gtkentryaction.h
===================================================================
RCS file: src/gtkentryaction.h
diff -N src/gtkentryaction.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/gtkentryaction.h	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (C) 2003 Marco Pesenti Gritti
+ *
+ *  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, 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.
+ *
+ *  $Id: ephy-location-action.h,v 1.11 2005/02/06 14:37:12 chpe Exp $
+ */
+
+#ifndef GTK_ENTRY_ACTION_H
+#define GTK_ENTRY_ACTION_H
+
+#include <gtk/gtkaction.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_ENTRY_ACTION            (gtk_entry_action_get_type ())
+#define GTK_ENTRY_ACTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_ACTION, GtkEntryAction))
+#define GTK_ENTRY_ACTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ENTRY_ACTION, GtkEntryActionClass))
+#define GTK_IS_ENTRY_ACTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ENTRY_ACTION))
+#define GTK_IS_ENTRY_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_ENTRY_ACTION))
+#define GTK_ENTRY_ACTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_ENTRY_ACTION, GtkEntryActionClass))
+
+typedef struct _GtkEntryAction		GtkEntryAction;
+typedef struct _GtkEntryActionPrivate	GtkEntryActionPrivate;
+typedef struct _GtkEntryActionClass		GtkEntryActionClass;
+
+struct _GtkEntryAction
+{
+	GtkAction parent;
+
+	/*< private >*/
+	GtkEntryActionPrivate *priv;
+};
+
+struct _GtkEntryActionClass
+{
+	GtkActionClass parent_class;
+};
+
+GType       gtk_entry_action_get_type  (void);
+
+GtkAction  *gtk_entry_action_new       (const gchar    *name,
+					const gchar    *label,
+					const gchar    *tooltip,
+					const gchar    *stock_id);
+
+const char *gtk_entry_action_get_text  (GtkEntryAction *action);
+
+void        gtk_entry_action_set_text  (GtkEntryAction *action,
+					const char     *text);
+
+G_END_DECLS
+
+#endif
Index: src/yelp-db-print-pager.c
===================================================================
RCS file: src/yelp-db-print-pager.c
diff -N src/yelp-db-print-pager.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/yelp-db-print-pager.c	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xinclude.h>
+#include <libxslt/xslt.h>
+#include <libxslt/templates.h>
+#include <libxslt/transform.h>
+#include <libxslt/extensions.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/xsltutils.h>
+
+#include "yelp-error.h"
+#include "yelp-db-print-pager.h"
+#include "yelp-toc-pager.h"
+#include "yelp-settings.h"
+
+#ifdef YELP_DEBUG
+#define d(x) x
+#else
+#define d(x)
+#endif
+
+#define STYLESHEET_PATH DATADIR"/yelp/xslt/"
+#define DB_STYLESHEET   STYLESHEET_PATH"db2html.xsl"
+#define DB_TITLE        STYLESHEET_PATH"db-title.xsl"
+
+#define BOOK_CHUNK_DEPTH 2
+#define ARTICLE_CHUNK_DEPTH 1
+
+#define EVENTS_PENDING while (yelp_pager_get_state (pager) <= YELP_PAGER_STATE_RUNNING && gtk_events_pending ()) gtk_main_iteration ();
+#define CANCEL_CHECK if (!main_running || yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR) goto done;
+
+extern gboolean main_running;
+
+#define YELP_DB_PRINT_PAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_DB_PRINT_PAGER, YelpDBPrintPagerPriv))
+
+struct _YelpDBPrintPagerPriv {
+    gchar          *root_id;
+};
+
+static void           db_print_pager_class_init   (YelpDBPrintPagerClass *klass);
+static void           db_print_pager_init         (YelpDBPrintPager      *pager);
+static void           db_print_pager_dispose      (GObject          *gobject);
+
+static void           db_print_pager_cancel       (YelpPager        *pager);
+static xmlDocPtr      db_print_pager_parse        (YelpPager        *pager);
+static gchar **       db_print_pager_params       (YelpPager        *pager);
+
+static const gchar *  db_print_pager_resolve_frag (YelpPager        *pager,
+					     const gchar      *frag_id);
+static GtkTreeModel * db_print_pager_get_sections (YelpPager        *pager);
+
+static YelpPagerClass *parent_class;
+
+GType
+yelp_db_print_pager_get_type (void)
+{
+    static GType type = 0;
+
+    if (!type) {
+	static const GTypeInfo info = {
+	    sizeof (YelpDBPrintPagerClass),
+	    NULL,
+	    NULL,
+	    (GClassInitFunc) db_print_pager_class_init,
+	    NULL,
+	    NULL,
+	    sizeof (YelpDBPrintPager),
+	    0,
+	    (GInstanceInitFunc) db_print_pager_init,
+	};
+	type = g_type_register_static (YELP_TYPE_XSLT_PAGER,
+				       "YelpDBPrintPager", 
+				       &info, 0);
+    }
+    return type;
+}
+
+static void
+db_print_pager_class_init (YelpDBPrintPagerClass *klass)
+{
+    GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+    YelpPagerClass *pager_class  = YELP_PAGER_CLASS (klass);
+    YelpXsltPagerClass *xslt_class = YELP_XSLT_PAGER_CLASS (klass);
+
+    parent_class = g_type_class_peek_parent (klass);
+
+    object_class->dispose = db_print_pager_dispose;
+
+    pager_class->cancel   = db_print_pager_cancel;
+
+    pager_class->resolve_frag = db_print_pager_resolve_frag;
+
+    xslt_class->parse  = db_print_pager_parse;
+    xslt_class->params = db_print_pager_params;
+
+    xslt_class->stylesheet = DB_STYLESHEET;
+
+    g_type_class_add_private (klass, sizeof (YelpDBPrintPagerPriv));
+}
+
+static void
+db_print_pager_init (YelpDBPrintPager *pager)
+{
+    YelpDBPrintPagerPriv *priv;
+
+    pager->priv = priv = YELP_DB_PRINT_PAGER_GET_PRIVATE (pager);
+
+    pager->priv->root_id = NULL;
+}
+
+static void
+db_print_pager_dispose (GObject *object)
+{
+    YelpDBPrintPager *pager = YELP_DB_PRINT_PAGER (object);
+
+    g_free (pager->priv->root_id);
+    g_free (pager->priv);
+
+    G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+/******************************************************************************/
+
+YelpPager *
+yelp_db_print_pager_new (YelpDocInfo *doc_info)
+{
+    YelpDBPrintPager *pager;
+
+    g_return_val_if_fail (doc_info != NULL, NULL);
+
+    pager = (YelpDBPrintPager *) g_object_new (YELP_TYPE_DB_PRINT_PAGER,
+					  "document-info", doc_info,
+					  NULL);
+
+    return (YelpPager *) pager;
+}
+
+static xmlDocPtr
+db_print_pager_parse (YelpPager *pager)
+{
+    YelpDBPrintPagerPriv *priv;
+    YelpDocInfo     *doc_info;
+    gchar           *filename = NULL;
+
+    xmlParserCtxtPtr parserCtxt = NULL;
+    xmlDocPtr doc = NULL;
+
+    xmlChar     *id;
+    GError      *error = NULL;
+
+    d (g_print ("db_print_pager_parse\n"));
+
+    doc_info = yelp_pager_get_doc_info (pager);
+
+    g_return_val_if_fail (pager != NULL, NULL);
+    g_return_val_if_fail (YELP_IS_DB_PRINT_PAGER (pager), NULL);
+    priv = YELP_DB_PRINT_PAGER (pager)->priv;
+
+    g_object_ref (pager);
+
+    if (yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR)
+	goto done;
+
+    filename = yelp_doc_info_get_filename (doc_info);
+
+    parserCtxt = xmlNewParserCtxt ();
+    doc = xmlCtxtReadFile (parserCtxt,
+			   (const char *) filename, NULL,
+			   XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
+			   XML_PARSE_NOENT   | XML_PARSE_NONET   );
+    if (doc == NULL) {
+	g_set_error (&error, YELP_ERROR, YELP_ERROR_NO_DOC,
+		     _("The file â??%sâ?? could not be parsed. Either the file "
+		       "does not exist, or it is not well-formed XML."),
+		     filename);
+	yelp_pager_error (pager, error);
+	goto done;
+    }
+
+    xmlXIncludeProcessFlags (doc,
+			     XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
+			     XML_PARSE_NOENT   | XML_PARSE_NONET   );
+
+
+    priv->root_id = g_strdup ("index");
+
+    EVENTS_PENDING;
+    CANCEL_CHECK;
+
+ done:
+    g_free (filename);
+
+    if (parserCtxt)
+	xmlFreeParserCtxt (parserCtxt);
+
+    g_object_unref (pager);
+
+    return doc;
+}
+
+static gchar **
+db_print_pager_params (YelpPager *pager)
+{
+    YelpDBPrintPagerPriv *priv;
+    YelpDocInfo     *doc_info;
+    gchar **params;
+    gint params_i = 0;
+    gint params_max = 20;
+
+    d (g_print ("db_print_pager_process\n"));
+
+    doc_info = yelp_pager_get_doc_info (pager);
+
+    g_return_val_if_fail (pager != NULL, FALSE);
+    g_return_val_if_fail (YELP_IS_DB_PRINT_PAGER (pager), FALSE);
+    priv = YELP_DB_PRINT_PAGER (pager)->priv;
+
+    if (yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR)
+	return NULL;
+
+    params = g_new0 (gchar *, params_max);
+
+    yelp_settings_params (&params, &params_i, &params_max);
+
+    if ((params_i + 10) >= params_max - 1) {
+	params_max += 20;
+	params = g_renew (gchar *, params, params_max);
+    }
+    params[params_i++] = "db.chunk.extension";
+    params[params_i++] = g_strdup ("\"\"");
+    params[params_i++] = "db.chunk.info_basename";
+    params[params_i++] = g_strdup ("\"x-yelp-titlepage\"");
+    params[params_i++] = "db.chunk.max_depth";
+    params[params_i++] = g_strdup_printf ("0");
+    params[params_i++] = "yelp.javascript";
+    params[params_i++] = g_strdup_printf ("\"%s\"", DATADIR "/yelp/yelp.js");
+
+    params[params_i] = NULL;
+
+    return params;
+}
+
+static void
+db_print_pager_cancel (YelpPager *pager)
+{
+    YelpDBPrintPagerPriv *priv = YELP_DB_PRINT_PAGER (pager)->priv;
+
+    d (g_print ("db_print_pager_cancel\n"));
+
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_INVALID);
+
+    g_free (priv->root_id);
+    priv->root_id = NULL;
+
+    YELP_PAGER_CLASS (parent_class)->cancel (pager);
+}
+
+static const gchar *
+db_print_pager_resolve_frag (YelpPager *pager, const gchar *frag_id)
+{
+    YelpDBPrintPager  *db_print_pager;
+
+    g_return_val_if_fail (pager != NULL, NULL);
+    g_return_val_if_fail (YELP_IS_DB_PRINT_PAGER (pager), NULL);
+
+    db_print_pager = YELP_DB_PRINT_PAGER (pager);
+
+    return db_print_pager->priv->root_id;
+}
+
Index: src/yelp-db-print-pager.h
===================================================================
RCS file: src/yelp-db-print-pager.h
diff -N src/yelp-db-print-pager.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/yelp-db-print-pager.h	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifndef __YELP_DB_PRINT_PAGER_H__
+#define __YELP_DB_PRINT_PAGER_H__
+
+#include <glib-object.h>
+
+#include "yelp-pager.h"
+#include "yelp-xslt-pager.h"
+
+#define YELP_TYPE_DB_PRINT_PAGER         (yelp_db_print_pager_get_type ())
+#define YELP_DB_PRINT_PAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_DB_PRINT_PAGER, YelpDBPrintPager))
+#define YELP_DB_PRINT_PAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_DB_PRINT_PAGER, YelpDBPrintPagerClass))
+#define YELP_IS_DB_PRINT_PAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_DB_PRINT_PAGER))
+#define YELP_IS_DB_PRINT_PAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_DB_PRINT_PAGER))
+#define YELP_DB_PRINT_PAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_DB_PRINT_PAGER, YelpDBPrintPagerClass))
+
+typedef struct _YelpDBPrintPager      YelpDBPrintPager;
+typedef struct _YelpDBPrintPagerClass YelpDBPrintPagerClass;
+typedef struct _YelpDBPrintPagerPriv  YelpDBPrintPagerPriv;
+
+struct _YelpDBPrintPager {
+    YelpXsltPager    parent;
+
+    YelpDBPrintPagerPriv *priv;
+};
+
+struct _YelpDBPrintPagerClass {
+    YelpXsltPagerClass   parent_class;
+};
+
+GType           yelp_db_print_pager_get_type     (void);
+YelpPager *     yelp_db_print_pager_new          (YelpDocInfo *doc_info);
+
+#endif /* __YELP_DB_PRINT_PAGER_H__ */
Index: src/yelp-html.cpp
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-html.cpp,v
retrieving revision 1.1
diff -u -p -r1.1 yelp-html.cpp
--- src/yelp-html.cpp	16 May 2005 21:02:33 -0000	1.1
+++ src/yelp-html.cpp	6 Jul 2005 19:30:56 -0000
@@ -34,14 +34,23 @@
 
 #include "Yelper.h"
 
+#include "gtkmozembed_internal.h"
+#include "nsIWebBrowserPrint.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+#include <libgnome/gnome-init.h>
+
 #ifdef GNOME_ENABLE_DEBUG
 #define d(x) x
 #else
-#define d(x)
+#define d(x) x
 #endif
 
 #define YELP_HTML_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_HTML, YelpHtmlPriv))
 
+#define MOZILLA_PROFILE_DIR  "/mozilla"
+#define MOZILLA_PROFILE_NAME "yelp"
+
 struct _YelpHtmlPriv {
     Yelper      *yelper;
     gchar       *base_uri;
@@ -51,6 +60,7 @@ struct _YelpHtmlPriv {
 static void      html_set_fonts          (void);
 static void      html_set_colors         (void);
 static void      html_set_a11y           (void);
+static void      open_new_window (GtkMozEmbed **newEmbed, guint chrome_mask);
 
 enum {
     URI_SELECTED,
@@ -120,6 +130,14 @@ html_realize (GtkWidget *widget)
 }
 
 static void
+html_new_window (GtkMozEmbed *embed,
+		 GtkMozEmbed **newEmbed,
+		 guint chrome_mask)
+{
+    open_new_window (newEmbed, chrome_mask);
+}
+
+static void
 html_init (YelpHtml *html)
 {
     YelpHtmlPriv  *priv;
@@ -197,6 +215,7 @@ html_class_init (YelpHtmlClass *klass)
     moz_embed_class->title = html_title;
     moz_embed_class->dom_mouse_down = html_dom_mouse_down;
     moz_embed_class->open_uri = html_open_uri;
+    moz_embed_class->new_window = html_new_window;
 
     klass->font_handler = 0;
 
@@ -305,7 +324,7 @@ yelp_html_write (YelpHtml *html, const g
      if (len == -1) len = strlen (data);
 
     d (g_print ("yelp_html_write\n"));
-    d (g_print ("  data = %i bytes\n", strlen (data)));
+    d (g_print ("  data = %*s\n", len, data));
     d (g_print ("  len  = %i\n", len));
 
     gtk_moz_embed_append_data (GTK_MOZ_EMBED (html),
@@ -385,6 +404,24 @@ yelp_html_select_all (YelpHtml *html)
     html->priv->yelper->DoCommand ("cmd_selectAll");
 }
 
+void
+yelp_html_print (YelpHtml *html)
+{
+    nsCOMPtr<nsIWebBrowser> webBrowser;
+
+    gtk_moz_embed_get_nsIWebBrowser  (GTK_MOZ_EMBED (html), getter_AddRefs(webBrowser));
+
+    if (webBrowser) {
+
+	nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(webBrowser));
+
+	if (print) {
+	    /* FIXME: Deal with retval. */
+	    print->Print (nsnull, nsnull);
+	}
+    }
+}
+
 static void
 html_set_fonts (void)
 {
@@ -421,4 +458,123 @@ html_set_a11y (void)
 
     caret = yelp_settings_get_caret ();
     yelp_gecko_set_caret (caret);
+}
+
+static void
+new_window_orphan_cb (GtkMozEmbedSingle *moz_single,
+		      GtkMozEmbed **newEmbed,
+		      guint chrome_mask,
+		      gpointer user_data)
+{
+    open_new_window (newEmbed, chrome_mask);
+}
+
+void
+yelp_html_initialize (void)
+{
+    static gboolean initialized = FALSE;
+    GtkMozEmbedSingle *single;
+    char *profile_path;
+
+    if (initialized)
+	return;
+    initialized = TRUE;
+
+    /* get single */
+    single = gtk_moz_embed_single_get ();
+    if (single == NULL) {
+	g_warning ("Failed to get singleton embed object!\n");
+    }
+
+    /* allow creation of orphan windows */
+    g_signal_connect (G_OBJECT (single), "new_window_orphan",
+		      G_CALLBACK (new_window_orphan_cb),
+		      NULL);
+
+    profile_path = g_build_filename (g_get_home_dir (),
+				     GNOME_DOT_GNOME,
+				     "yelp.d",
+				     MOZILLA_PROFILE_DIR, 
+				     NULL);
+    gtk_moz_embed_set_profile_path (profile_path, MOZILLA_PROFILE_NAME);
+    g_free (profile_path);
+}
+
+static GtkMozEmbed *new_xul_dialog (void);
+
+static void
+xul_visibility_cb (GtkWidget *embed, gboolean visibility, GtkWidget *window)
+{
+    if (visibility) {
+	gtk_widget_show (window);
+    } else {
+	gtk_widget_hide (window);
+    }
+}
+
+static void
+xul_size_to_cb (GtkWidget *embed, gint width, gint height, gpointer dummy)
+{
+        gtk_widget_set_size_request (embed, width, height);
+}
+
+static void
+xul_new_window_cb (GtkMozEmbed *embed,
+                   GtkMozEmbed **retval,
+                   guint chrome_mask,
+                   gpointer dummy)
+{
+    g_assert (chrome_mask & GTK_MOZ_EMBED_FLAG_OPENASCHROME);
+
+    *retval = new_xul_dialog ();
+}
+
+static void
+xul_title_cb (GtkMozEmbed *embed,
+              GtkWindow *window)
+{
+    char *title;
+
+    title = gtk_moz_embed_get_title (embed);
+    gtk_window_set_title (window, title);
+    g_free (title);
+}
+
+static GtkMozEmbed *
+new_xul_dialog (void)
+{
+    GtkWidget *window, *embed;
+
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    embed = gtk_moz_embed_new ();
+    gtk_widget_show (embed);
+    gtk_container_add (GTK_CONTAINER (window), embed);
+
+    g_signal_connect_object (embed, "destroy_browser",
+			     G_CALLBACK (gtk_widget_destroy),
+			     window, G_CONNECT_SWAPPED);
+    g_signal_connect_object (embed, "visibility",
+			     G_CALLBACK (xul_visibility_cb),
+			     window, (GConnectFlags) 0);
+    g_signal_connect_object (embed, "size_to",
+			     G_CALLBACK (xul_size_to_cb),
+			     NULL, (GConnectFlags) 0);
+    g_signal_connect_object (embed, "new_window",
+			     G_CALLBACK (xul_new_window_cb),
+			     NULL, (GConnectFlags) 0);
+    g_signal_connect_object (embed, "title",
+			     G_CALLBACK (xul_title_cb),
+			     window, (GConnectFlags) 0);
+
+    return GTK_MOZ_EMBED (embed);
+}
+
+static void
+open_new_window (GtkMozEmbed **newEmbed,
+		 guint chrome_mask)
+{
+    if (chrome_mask & GTK_MOZ_EMBED_FLAG_OPENASCHROME) {
+	*newEmbed = new_xul_dialog ();
+	return;
+    }
 }
Index: src/yelp-html.h
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-html.h,v
retrieving revision 1.30
diff -u -p -r1.30 yelp-html.h
--- src/yelp-html.h	16 May 2005 21:02:33 -0000	1.30
+++ src/yelp-html.h	6 Jul 2005 19:30:56 -0000
@@ -98,6 +98,10 @@ void            yelp_html_copy_selection
 
 void            yelp_html_select_all     (YelpHtml    *html);
 
+void            yelp_html_print          (YelpHtml    *html);
+
+void            yelp_html_initialize     (void);
+
 G_END_DECLS
 
 #endif /* __YELP_HTML_H__ */
Index: src/yelp-main.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-main.c,v
retrieving revision 1.38
diff -u -p -r1.38 yelp-main.c
--- src/yelp-main.c	6 Mar 2005 20:07:11 -0000	1.38
+++ src/yelp-main.c	6 Jul 2005 19:30:56 -0000
@@ -42,6 +42,8 @@
 #include "GNOME_Yelp.h"
 #include "yelp-window.h"
 #include "yelp-base.h"
+#include "yelp-html.h"
+#include "yelp-toc.h"
 
 #define YELP_FACTORY_OAFIID "OAFIID:GNOME_Yelp_Factory"
 
@@ -365,6 +367,8 @@ main (int argc, char **argv) 
 	if (!factory) { /* Not started, start now */ 
 		BonoboGenericFactory *factory;
 		char                 *registration_id;
+
+		yelp_html_initialize ();
 
 		registration_id = bonobo_activation_make_registration_id (
 					YELP_FACTORY_OAFIID,
Index: src/yelp-search-pager.c
===================================================================
RCS file: src/yelp-search-pager.c
diff -N src/yelp-search-pager.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/yelp-search-pager.c	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,722 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xmlreader.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/tree.h>
+#include <libxslt/xslt.h>
+#include <libxslt/templates.h>
+#include <libxslt/transform.h>
+#include <libxslt/extensions.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/xsltutils.h>
+
+#include <beagle/beagle.h>
+
+#include "yelp-error.h"
+#include "yelp-settings.h"
+#include "yelp-search-pager.h"
+#include "yelp-utils.h"
+
+#define DESKTOP_ENTRY_GROUP     "Desktop Entry"
+#define KDE_DESKTOP_ENTRY_GROUP "KDE Desktop Entry"
+
+#ifdef YELP_DEBUG
+#define d(x) x
+#else
+#define d(x) x
+#endif
+
+#define YELP_NAMESPACE "http://www.gnome.org/yelp/ns";
+
+#define STYLESHEET_PATH DATADIR"/yelp/xslt/"
+#define SEARCH_STYLESHEET  STYLESHEET_PATH"search2html.xsl"
+
+typedef gboolean      (*ProcessFunction)        (YelpSearchPager      *pager);
+
+typedef struct _YelpListing YelpListing;
+
+#define YELP_SEARCH_PAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_SEARCH_PAGER, YelpSearchPagerPriv))
+
+struct _YelpSearchPagerPriv {
+    xmlDocPtr     search_doc;
+    xmlNodePtr    root;
+
+    xmlParserCtxtPtr  parser;
+
+    gboolean      cancel;
+
+    xsltStylesheetPtr       stylesheet;
+    xsltTransformContextPtr transformContext;
+    char *search_terms;
+    gboolean hits_finished;
+    int   snippet_request_count;
+};
+
+struct _YelpListing {
+    gchar       *id;
+    gchar       *title;
+
+    GSList      *listings;
+    GSList      *documents;
+
+    gboolean     has_listings;
+};
+
+static void          search_pager_class_init      (YelpSearchPagerClass *klass);
+static void          search_pager_init            (YelpSearchPager      *pager);
+static void          search_pager_dispose         (GObject           *gobject);
+
+static void          search_pager_error           (YelpPager        *pager);
+static void          search_pager_cancel          (YelpPager        *pager);
+static void          search_pager_finish          (YelpPager        *pager);
+
+gboolean             search_pager_process         (YelpPager         *pager);
+void                 search_pager_cancel          (YelpPager         *pager);
+const gchar *        search_pager_resolve_frag    (YelpPager         *pager,
+						const gchar       *frag_id);
+GtkTreeModel *       search_pager_get_sections    (YelpPager         *pager);
+
+static gboolean      process_xslt              (YelpSearchPager      *pager);
+
+static void          xslt_yelp_document        (xsltTransformContextPtr ctxt,
+						xmlNodePtr              node,
+						xmlNodePtr              inst,
+						xsltStylePreCompPtr     comp);
+static gboolean      search_pager_process_idle (YelpSearchPager        *pager);
+
+static YelpPagerClass *parent_class;
+
+static BeagleClient   *beagle_client;
+
+GType
+yelp_search_pager_get_type (void)
+{
+    static GType type = 0;
+
+    if (!type) {
+	static const GTypeInfo info = {
+	    sizeof (YelpSearchPagerClass),
+	    NULL,
+	    NULL,
+	    (GClassInitFunc) search_pager_class_init,
+	    NULL,
+	    NULL,
+	    sizeof (YelpSearchPager),
+	    0,
+	    (GInstanceInitFunc) search_pager_init,
+	};
+	type = g_type_register_static (YELP_TYPE_PAGER,
+				       "YelpSearchPager", 
+				       &info, 0);
+    }
+    return type;
+}
+
+static void
+search_pager_class_init (YelpSearchPagerClass *klass)
+{
+    GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+    YelpPagerClass *pager_class  = YELP_PAGER_CLASS (klass);
+
+    parent_class = g_type_class_peek_parent (klass);
+
+    beagle_client = beagle_client_new (NULL);
+
+    object_class->dispose = search_pager_dispose;
+
+    pager_class->error        = search_pager_error;
+    pager_class->cancel       = search_pager_cancel;
+    pager_class->finish       = search_pager_finish;
+
+    pager_class->process      = search_pager_process;
+    pager_class->cancel       = search_pager_cancel;
+    pager_class->resolve_frag = search_pager_resolve_frag;
+    pager_class->get_sections = search_pager_get_sections;
+
+    g_type_class_add_private (klass, sizeof (YelpSearchPagerPriv));
+}
+
+static void
+search_pager_init (YelpSearchPager *pager)
+{
+    YelpSearchPagerPriv *priv;
+
+    pager->priv = priv = YELP_SEARCH_PAGER_GET_PRIVATE (pager);
+
+    priv->parser = xmlNewParserCtxt ();
+
+    priv->cancel       = 0;
+    priv->search_terms = NULL;
+    priv->hits_finished = FALSE;
+    priv->snippet_request_count = 0;
+}
+
+static void
+search_pager_dispose (GObject *object)
+{
+    YelpSearchPager *pager = YELP_SEARCH_PAGER (object);
+
+    g_free (pager->priv);
+
+    G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+/******************************************************************************/
+
+static gboolean
+check_hex (char check)
+{
+    if (check >= '0' && check <= '9')
+	return TRUE;
+    if (check >= 'a' && check <= 'f')
+	return TRUE;
+    if (check >= 'A' && check <= 'F')
+	return TRUE;
+    return FALSE;
+}
+
+static int
+conv_hex (char conv)
+{
+    if (conv >= '0' && conv <= '9')
+	return conv - '0';
+    if (conv >= 'a' && conv <= 'f')
+	return conv - 'a' + 10;
+    if (conv >= 'A' && conv <= 'F')
+	return conv - 'A' + 10;
+    return 0;
+}
+
+static char *
+decode_uri (const char *uri)
+{
+    char *decoded = g_strdup (uri);
+    char *iterator;
+
+    for (iterator = decoded; *iterator; iterator ++) {
+	if (*iterator == '%' && check_hex (iterator[1]) && check_hex(iterator[2])) {
+	    *iterator = conv_hex (iterator[1]) * 16 + conv_hex (iterator[2]);
+	    memmove (iterator + 1, iterator + 3, strlen (iterator + 3));
+	}
+    }
+
+    return decoded;
+}
+
+YelpSearchPager *
+yelp_search_pager_get (YelpDocInfo *doc_info)
+{
+    static GHashTable *search_hash;
+    YelpSearchPager *search_pager;
+    char *uri;
+    char *search_terms;
+
+    if (search_hash == NULL) {
+	search_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+					     NULL,       g_object_unref);
+    }
+
+    uri = yelp_doc_info_get_uri (doc_info, NULL, YELP_URI_TYPE_SEARCH);
+    search_terms = decode_uri (uri + strlen ("x-yelp-search:"));
+    g_free (uri);
+
+    search_pager = g_hash_table_lookup (search_hash, search_terms);
+
+    if (search_pager == NULL) {
+	search_pager = (YelpSearchPager *) g_object_new (YELP_TYPE_SEARCH_PAGER,
+							 "document-info", doc_info,
+							 NULL);
+	search_pager->priv->search_terms = search_terms;
+	g_hash_table_insert (search_hash, search_terms, search_pager);
+	yelp_pager_start (YELP_PAGER (search_pager));
+    } else {
+	g_free (search_terms);
+    }
+
+    g_object_ref (search_pager);
+    return search_pager;
+}
+
+/******************************************************************************/
+
+static void
+search_pager_error (YelpPager *pager)
+{
+    d (g_print ("search_pager_error\n"));
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_ERROR);
+}
+
+static void
+search_pager_cancel (YelpPager *pager)
+{
+    YelpSearchPagerPriv *priv = YELP_SEARCH_PAGER (pager)->priv;
+
+    d (g_print ("search_pager_cancel\n"));
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_INVALID);
+
+    priv->cancel = TRUE;
+}
+
+static void
+search_pager_finish (YelpPager   *pager)
+{
+    d (g_print ("search_pager_finish\n"));
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_FINISHED);
+}
+
+gboolean
+search_pager_process (YelpPager *pager)
+{
+    d (g_print ("search_pager_process\n"));
+
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_PARSING);
+    g_signal_emit_by_name (pager, "parse");
+
+    /* Set it running */
+    yelp_pager_set_state (pager, YELP_PAGER_STATE_RUNNING);
+    g_signal_emit_by_name (pager, "start");
+
+    gtk_idle_add_priority (G_PRIORITY_LOW,
+			   (GtkFunction) search_pager_process_idle,
+			   pager);
+    return FALSE;
+}
+
+const gchar *
+search_pager_resolve_frag (YelpPager *pager, const gchar *frag_id)
+{
+    if (!frag_id)
+	return "results";
+    else
+	return frag_id;
+}
+
+GtkTreeModel *
+search_pager_get_sections (YelpPager *pager)
+{
+    return NULL;
+}
+
+/******************************************************************************/
+
+static void
+check_finished (YelpSearchPager *pager)
+{
+    if (pager->priv->snippet_request_count == 0 && pager->priv->hits_finished) {
+	gtk_idle_add_priority (G_PRIORITY_LOW,
+			       (GtkFunction) process_xslt,
+			       pager);
+    }
+}
+
+typedef struct
+{
+    YelpSearchPager *pager;
+    xmlNode *node;
+} SnippetLocation;
+
+static void
+snippet_closed (BeagleSnippetRequest *request, SnippetLocation *snippet_location)
+{
+    YelpSearchPager *pager = snippet_location->pager;
+    
+    g_print ("snippet_closed\n");
+
+    pager->priv->snippet_request_count --;
+    check_finished (pager);
+    g_free (snippet_location);
+    g_object_unref (request);
+}
+
+static void
+snippet_response (BeagleSnippetRequest *request, BeagleSnippetResponse *response, SnippetLocation *snippet_location)
+{
+    g_print ("snippet_response: %s\n", beagle_snippet_response_get_snippet (response));
+    xmlSetProp (snippet_location->node, "snippet", beagle_snippet_response_get_snippet (response));
+    snippet_closed (request, snippet_location);
+}
+
+static void
+snippet_error (BeagleSnippetRequest *request, GError *error, SnippetLocation *snippet_location)
+{
+    g_print ("snippet_error\n");
+    snippet_closed (request, snippet_location);
+}
+
+static void
+hits_added_cb (BeagleQuery *query, BeagleHitsAddedResponse *response, YelpSearchPager *pager)
+{
+    YelpSearchPagerPriv *priv = YELP_SEARCH_PAGER (pager)->priv;
+
+    GSList *hits, *l;
+    gint    i;
+
+    hits = beagle_hits_added_response_get_hits (response);
+
+    for (l = hits, i = 1; l; l = l->next, ++i) {
+	BeagleHit *hit = l->data;
+	xmlNode *child;
+	char *score;
+	BeagleSnippetRequest *request;
+	SnippetLocation *snippet_location;
+
+	child = xmlNewTextChild (priv->root, NULL, "result", NULL);
+	xmlSetProp (child, "uri", beagle_hit_get_uri (hit));
+
+	score = g_strdup_printf ("%lf", beagle_hit_get_score (hit));
+	xmlSetProp (child, "score", score);
+	g_free (score);
+
+	priv->snippet_request_count ++;
+
+	snippet_location = g_new (SnippetLocation, 1);
+
+	snippet_location->pager = pager;
+	snippet_location->node = child;
+
+	request = beagle_snippet_request_new ();
+	beagle_snippet_request_set_hit (request, hit);
+	beagle_snippet_request_add_query_term (request, priv->search_terms);
+
+	g_signal_connect (request, "response",
+			  G_CALLBACK (snippet_response), snippet_location);
+	g_signal_connect (request, "error",
+			  G_CALLBACK (snippet_error), snippet_location);
+	g_signal_connect (request, "closed",
+			  G_CALLBACK (snippet_closed), snippet_location);
+
+	beagle_client_send_request_async (beagle_client, BEAGLE_REQUEST (request),
+					  NULL);
+
+    }
+}
+
+static void
+finished_cb (BeagleQuery            *query,
+	     BeagleFinishedResponse *response, 
+	     YelpSearchPager        *pager)
+{
+    pager->priv->hits_finished = TRUE;
+    check_finished (pager);
+}
+
+static gboolean
+search_pager_process_idle (YelpSearchPager *pager)
+{
+    BeagleQuery    *query;
+    YelpSearchPagerPriv *priv = YELP_SEARCH_PAGER (pager)->priv;
+
+    priv->search_doc = xmlNewDoc ("1.0");
+    priv->root = xmlNewNode (NULL, "search");
+    xmlSetProp (priv->root, "title", priv->search_terms);
+    xmlDocSetRootElement (priv->search_doc, priv->root);
+
+    query = beagle_query_new ();
+
+    beagle_query_add_text (query, priv->search_terms);
+    /*    beagle_query_add_hit_type (query, "DocBookEntry");*/
+
+    g_signal_connect (query, "hits-added",
+		      G_CALLBACK (hits_added_cb),
+		      pager);
+    
+    g_signal_connect (query, "finished",
+		      G_CALLBACK (finished_cb),
+		      pager);
+	
+    beagle_client_send_request_async (beagle_client, BEAGLE_REQUEST (query),
+				      NULL);
+
+    return FALSE;
+}
+
+static gboolean
+process_xslt (YelpSearchPager *pager)
+{
+    GError *error = NULL;
+    xmlDocPtr outdoc = NULL;
+    YelpSearchPagerPriv *priv = pager->priv;
+    gchar **params;
+    gint  params_i = 0;
+    gint  params_max = 12;
+    GtkIconInfo *info;
+    GtkIconTheme *theme = (GtkIconTheme *) yelp_settings_get_icon_theme ();
+
+    d(xmlDocFormatDump(stdout, priv->search_doc, 1));
+
+    priv->stylesheet = xsltParseStylesheetFile (SEARCH_STYLESHEET);
+    if (!priv->stylesheet) {
+	g_set_error (&error, YELP_ERROR, YELP_ERROR_PROC,
+		     _("The table of contents could not be processed. The "
+		       "file â??%sâ?? is either missing or is not a valid XSLT "
+		       "stylesheet."),
+		     SEARCH_STYLESHEET);
+	yelp_pager_error (YELP_PAGER (pager), error);
+	goto done;
+    }
+
+    priv->transformContext = xsltNewTransformContext (priv->stylesheet,
+						      priv->search_doc);
+    priv->transformContext->_private = pager;
+    xsltRegisterExtElement (priv->transformContext,
+			    "document",
+			    YELP_NAMESPACE,
+			    (xsltTransformFunction) xslt_yelp_document);
+
+    params = g_new0 (gchar *, params_max);
+    yelp_settings_params (&params, &params_i, &params_max);
+
+    if ((params_i + 12) >= params_max - 1) {
+	params_max += 12;
+	params = g_renew (gchar *, params, params_max);
+    }
+
+    info = gtk_icon_theme_lookup_icon (theme, "yelp-icon-big", 192, 0);
+    if (info) {
+	params[params_i++] = "help_icon";
+	params[params_i++] = g_strdup_printf ("\"%s\"",
+					      gtk_icon_info_get_filename (info));
+	params[params_i++] = "help_icon_size";
+	params[params_i++] = g_strdup_printf ("%i",
+					      gtk_icon_info_get_base_size (info));
+	gtk_icon_info_free (info);
+    }
+
+    params[params_i++] = "yelp.javascript";
+    params[params_i++] = g_strdup_printf ("\"%s\"", DATADIR "/yelp/yelp.js");
+
+    params[params_i++] = NULL;
+
+    outdoc = xsltApplyStylesheetUser (priv->stylesheet,
+				      priv->search_doc,
+				      (const gchar **)params, NULL, NULL,
+				      priv->transformContext);
+    /* Don't do this */
+    /*    g_signal_emit_by_name (pager, "finish");*/
+
+ done:
+    for (params_i = 0; params[params_i] != NULL; params_i++)
+	if (params_i % 2 == 1)
+	    g_free ((gchar *) params[params_i]);
+    if (outdoc)
+	xmlFreeDoc (outdoc);
+    if (priv->search_doc) {
+	xmlFreeDoc (priv->search_doc);
+	priv->search_doc = NULL;
+    }
+    if (priv->stylesheet) {
+	xsltFreeStylesheet (priv->stylesheet);
+	priv->stylesheet = NULL;
+    }
+    if (priv->transformContext) {
+	xsltFreeTransformContext (priv->transformContext);
+	priv->transformContext = NULL;
+    }
+
+    g_signal_emit_by_name (pager, "finish");
+    return FALSE;
+}
+
+static void
+xslt_yelp_document (xsltTransformContextPtr ctxt,
+		    xmlNodePtr              node,
+		    xmlNodePtr              inst,
+		    xsltStylePreCompPtr     comp)
+{
+    GError  *error;
+    YelpPage *page;
+    xmlChar *page_id = NULL;
+    xmlChar *page_title = NULL;
+    xmlChar *page_buf;
+    gint     buf_size;
+    YelpPager *pager;
+    xsltStylesheetPtr style = NULL;
+    const char *old_outfile;
+    xmlDocPtr   new_doc = NULL;
+    xmlDocPtr   old_doc;
+    xmlNodePtr  old_insert;
+    xmlNodePtr  cur;
+
+    if (!ctxt || !node || !inst || !comp)
+	return;
+
+    pager = (YelpPager *) ctxt->_private;
+
+    page_id = xsltEvalAttrValueTemplate (ctxt, inst,
+					 (const xmlChar *) "href",
+					 NULL);
+    if (page_id == NULL) {
+	xsltTransformError (ctxt, NULL, inst,
+			    _("No href attribute found on yelp:document"));
+	error = NULL;
+	yelp_pager_error (pager, error);
+	goto done;
+    }
+
+    old_outfile = ctxt->outputFile;
+    old_doc     = ctxt->output;
+    old_insert  = ctxt->insert;
+    ctxt->outputFile = (const char *) page_id;
+
+    style = xsltNewStylesheet ();
+    if (style == NULL) {
+	xsltTransformError (ctxt, NULL, inst,
+			    _("Out of memory"));
+	error = NULL;
+	yelp_pager_error (pager, error);
+	goto done;
+    }
+
+    style->omitXmlDeclaration = TRUE;
+
+    new_doc = xmlNewDoc ("1.0");
+    new_doc->charset = XML_CHAR_ENCODING_UTF8;
+    new_doc->dict = ctxt->dict;
+    xmlDictReference (new_doc->dict);
+
+    ctxt->output = new_doc;
+    ctxt->insert = (xmlNodePtr) new_doc;
+
+    xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL);
+
+    xsltSaveResultToString (&page_buf, &buf_size, new_doc, style);
+
+    ctxt->outputFile = old_outfile;
+    ctxt->output     = old_doc;
+    ctxt->insert     = old_insert;
+
+    for (cur = node->children; cur; cur = cur->next) {
+	if (!xmlStrcmp (cur->name, BAD_CAST "title")) {
+	    page_title = xmlNodeGetContent (cur);
+	    break;
+	}
+    }
+
+    page = g_new0 (YelpPage, 1);
+
+    if (page_id) {
+	page->page_id = g_strdup (page_id);
+	xmlFree (page_id);
+    }
+    if (page_title) {
+	page->title = g_strdup (page_title);
+	xmlFree (page_title);
+    } else {
+	page->title = g_strdup (_("Help Contents"));
+    }
+    page->contents = page_buf;
+
+    cur = xmlDocGetRootElement (new_doc);
+    for (cur = cur->children; cur; cur = cur->next) {
+	if (!xmlStrcmp (cur->name, (xmlChar *) "head")) {
+	    for (cur = cur->children; cur; cur = cur->next) {
+		if (!xmlStrcmp (cur->name, (xmlChar *) "link")) {
+		    xmlChar *rel = xmlGetProp (cur, "rel");
+
+		    if (!xmlStrcmp (rel, (xmlChar *) "Previous"))
+			page->prev_id = xmlGetProp (cur, "href");
+		    else if (!xmlStrcmp (rel, (xmlChar *) "Next"))
+			page->next_id = xmlGetProp (cur, "href");
+		    else if (!xmlStrcmp (rel, (xmlChar *) "Top"))
+			page->toc_id = xmlGetProp (cur, "href");
+
+		    xmlFree (rel);
+		}
+	    }
+	    break;
+	}
+    }
+
+    yelp_pager_add_page (pager, page);
+    g_signal_emit_by_name (pager, "page", page->page_id);
+
+ done:
+    if (new_doc)
+	xmlFreeDoc (new_doc);
+    if (style)
+	xsltFreeStylesheet (style);
+}
+
+#ifdef ENABLE_SCROLLKEEPER
+static void
+xml_trim_titles (xmlNodePtr node)
+{
+    xmlNodePtr cur, keep = NULL;
+    xmlChar *keep_lang = NULL;
+    int j, keep_pri = INT_MAX;
+
+    const gchar * const * langs = g_get_language_names ();
+
+    for (cur = node->children; cur; cur = cur->next) {
+	if (!xmlStrcmp (cur->name, BAD_CAST "title")) {
+	    xmlChar *cur_lang = NULL;
+	    int cur_pri = INT_MAX;
+	    cur_lang = xmlNodeGetLang (cur);
+	    if (cur_lang) {
+		for (j = 0; langs[j]; j++) {
+		    if (g_str_equal (cur_lang, langs[j])) {
+			cur_pri = j;
+			break;
+		    }
+		}
+	    } else {
+		cur_pri = INT_MAX - 1;
+	    }
+	    if (cur_pri <= keep_pri) {
+		if (keep_lang)
+		    xmlFree (keep_lang);
+		keep_lang = cur_lang;
+		keep_pri = cur_pri;
+		keep = cur;
+	    } else {
+		if (cur_lang)
+		    xmlFree (cur_lang);
+	    }
+	}
+    }
+    cur = node->children;
+    while (cur) {
+	xmlNodePtr this = cur;
+	cur = cur->next;
+	if (!xmlStrcmp (this->name, BAD_CAST "title")) {
+	    if (this != keep) {
+		xmlUnlinkNode (this);
+		xmlFreeNode (this);
+	    }
+	}
+    }
+    xmlFree (keep_lang);
+}
+#endif
Index: src/yelp-search-pager.h
===================================================================
RCS file: src/yelp-search-pager.h
diff -N src/yelp-search-pager.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/yelp-search-pager.h	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifndef __YELP_SEARCH_PAGER_H__
+#define __YELP_SEARCH_PAGER_H__
+
+#include <glib-object.h>
+
+#include "yelp-pager.h"
+
+#define YELP_TYPE_SEARCH_PAGER         (yelp_search_pager_get_type ())
+#define YELP_SEARCH_PAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_SEARCH_PAGER, YelpSearchPager))
+#define YELP_SEARCH_PAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_SEARCH_PAGER, YelpSearchPagerClass))
+#define YELP_IS_SEARCH_PAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_SEARCH_PAGER))
+#define YELP_IS_SEARCH_PAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_SEARCH_PAGER))
+#define YELP_SEARCH_PAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_SEARCH_PAGER, YelpSearchPagerClass))
+
+typedef struct _YelpSearchPager      YelpSearchPager;
+typedef struct _YelpSearchPagerClass YelpSearchPagerClass;
+typedef struct _YelpSearchPagerPriv  YelpSearchPagerPriv;
+
+struct _YelpSearchPager {
+    YelpPager         parent;
+
+    YelpSearchPagerPriv *priv;
+};
+
+struct _YelpSearchPagerClass {
+    YelpPagerClass    parent_class;
+};
+
+GType            yelp_search_pager_get_type     (void);
+
+void             yelp_search_pager_init         (void);
+YelpSearchPager *yelp_search_pager_get          (YelpDocInfo *doc_info);
+
+#endif /* __YELP_SEARCH_PAGER_H__ */
Index: src/yelp-toc-pager.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-toc-pager.c,v
retrieving revision 1.47
diff -u -p -r1.47 yelp-toc-pager.c
--- src/yelp-toc-pager.c	19 May 2005 22:41:16 -0000	1.47
+++ src/yelp-toc-pager.c	6 Jul 2005 19:30:56 -0000
@@ -34,6 +34,7 @@
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 #include <libxml/HTMLtree.h>
+#include <libxml/tree.h>
 #include <libxslt/xslt.h>
 #include <libxslt/templates.h>
 #include <libxslt/transform.h>
@@ -46,6 +47,12 @@
 #include "yelp-toc-pager.h"
 #include "yelp-utils.h"
 
+#define GMENU_I_KNOW_THIS_IS_UNSTABLE
+#include <gmenu-tree.h>
+
+#define DESKTOP_ENTRY_GROUP     "Desktop Entry"
+#define KDE_DESKTOP_ENTRY_GROUP "KDE Desktop Entry"
+
 #ifdef YELP_DEBUG
 #define d(x) x
 #else
@@ -96,6 +103,9 @@ struct _YelpTocPagerPriv {
 
     xsltStylesheetPtr       stylesheet;
     xsltTransformContextPtr transformContext;
+
+    GMenuTree *libmenu_tree;
+    GSList *libmenu_stack;
 };
 
 struct _YelpListing {
@@ -125,10 +135,14 @@ GtkTreeModel *       toc_pager_get_secti
 static gboolean      toc_process_pending       (YelpTocPager      *pager);
 
 
-static gboolean      process_read_menu         (YelpTocPager      *pager);
+static gboolean      process_libmenu           (YelpTocPager      *pager);
+static gboolean      process_libmenu_node      (YelpTocPager      *pager);
 static gboolean      process_xslt              (YelpTocPager      *pager);
+#ifdef ENABLE_SCROLLKEEPER
+static gboolean      process_read_menu         (YelpTocPager      *pager);
 static gboolean      process_read_scrollkeeper (YelpTocPager      *pager);
 static gboolean      process_omf_pending       (YelpTocPager      *pager);
+#endif
 #ifdef ENABLE_MAN
 static gboolean      process_mandir_pending    (YelpTocPager      *pager);
 #endif
@@ -137,11 +151,13 @@ static gboolean      process_info_dir_pe
 static gboolean      process_info_pending      (YelpTocPager      *pager);
 #endif
 
+#ifdef ENABLE_SCROLLKEEPER
 static void          toc_add_doc_info          (YelpTocPager      *pager,
 						YelpDocInfo       *doc_info);
 static void          toc_remove_doc_info       (YelpTocPager      *pager,
 						YelpDocInfo       *doc_info);
 static void          xml_trim_titles           (xmlNodePtr         node);
+#endif
 static void          xslt_yelp_document        (xsltTransformContextPtr ctxt,
 						xmlNodePtr              node,
 						xmlNodePtr              inst,
@@ -213,6 +229,9 @@ toc_pager_init (YelpTocPager *pager)
     priv->cancel       = 0;
     priv->pause_count  = 0;
     priv->pending_func = NULL;
+
+    priv->libmenu_tree  = NULL;
+    priv->libmenu_stack = NULL;
 }
 
 static void
@@ -320,7 +339,7 @@ toc_pager_process (YelpPager *pager)
     yelp_pager_set_state (pager, YELP_PAGER_STATE_RUNNING);
     g_signal_emit_by_name (pager, "start");
 
-    priv->pending_func = (ProcessFunction) process_read_menu;
+    priv->pending_func = (ProcessFunction) process_libmenu;
 
     gtk_idle_add_priority (G_PRIORITY_LOW,
 			   (GtkFunction) toc_process_pending,
@@ -351,10 +370,15 @@ toc_process_pending (YelpTocPager *pager
     gboolean readd;
     YelpTocPagerPriv *priv = pager->priv;
     static gpointer process_funcs[] = {
+	process_libmenu,
+	process_libmenu_node,
+	process_xslt,
+#ifdef ENABLE_SCROLLKEEPER
 	process_read_menu,
 	process_read_scrollkeeper,
 	process_omf_pending,
 	process_xslt,
+#endif
 #ifdef ENABLE_MAN
 	process_mandir_pending,
 	process_xslt,
@@ -386,6 +410,303 @@ toc_process_pending (YelpTocPager *pager
 	return FALSE;
 }
 
+static void
+set_icon (xmlNode *node, const char *icon)
+{
+    if (icon) {
+	GtkIconInfo *info;
+	GtkIconTheme *theme = 
+	    (GtkIconTheme *) yelp_settings_get_icon_theme ();
+	info = gtk_icon_theme_lookup_icon (theme, icon, 48, 0);
+	if (info) {
+	    xmlNodePtr new = xmlNewChild (node, NULL, "icon", NULL);
+	    xmlNewNsProp (new, NULL, "file", gtk_icon_info_get_filename (info));
+	    gtk_icon_info_free (info);
+	}
+    }
+}
+
+typedef struct {
+    xmlNode *tree;
+    GSList *children;
+    GSList *iterator;
+    gboolean non_empty;
+} LibmenuStackFrame;
+
+static void
+push_stack_frame (YelpTocPager *pager, GMenuTreeDirectory *dir)
+{
+    LibmenuStackFrame *frame;
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+
+    frame = g_new (LibmenuStackFrame, 1);
+    frame->iterator = frame->children = gmenu_tree_directory_get_contents (dir);
+    frame->non_empty = FALSE;
+
+    frame->tree = xmlNewNode (NULL, "toc");
+    xmlSetProp (frame->tree, "id", gmenu_tree_directory_get_menu_id (dir));
+    xmlNewTextChild (frame->tree, NULL, "title", gmenu_tree_directory_get_name (dir));
+    set_icon (frame->tree, gmenu_tree_directory_get_icon (dir));
+
+    priv->libmenu_stack = g_slist_prepend (priv->libmenu_stack, frame);
+}
+
+static void
+pop_stack_frame (YelpTocPager *pager)
+{
+    LibmenuStackFrame *frame;
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+
+    frame = priv->libmenu_stack->data;
+
+    g_slist_free (frame->children);
+    g_free (frame);
+
+    priv->libmenu_stack = g_slist_delete_link (priv->libmenu_stack, priv->libmenu_stack);
+}
+
+static GTimer *timer;
+/* iterator points to next node to process and is incremented at the
+   end of the function.  NULL means finished with this level.  Parent
+   iterators are incremented before processing the child tree. */
+static gboolean
+process_libmenu_node (YelpTocPager *pager)
+{
+    LibmenuStackFrame *frame;
+    GMenuTreeItem *item;
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+    gulong ms_start;
+
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed (enter process_libmenu_node) ", ms);
+	    ms_start = ms;
+}
+
+    frame = priv->libmenu_stack->data;
+
+    if (frame->iterator == NULL) {
+	g_print ("pop");
+	if (priv->libmenu_stack->next) {
+	    if (frame->non_empty) {
+		xmlNode *tree = frame->tree;
+		pop_stack_frame (pager);
+
+		frame = priv->libmenu_stack->data;
+		xmlAddChild (frame->tree, tree);
+		frame->non_empty = TRUE;
+	    } else {
+		xmlFreeNode (frame->tree);
+		pop_stack_frame(pager);
+	    }
+
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("\n%ld elapsed (exit process_libmenu_node (%ld))\n", ms, ((glong)ms - ms_start) % 1000000);
+}
+	    return TRUE;
+	} else {
+	    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+
+	    priv->toc_doc = xmlNewDoc ("1.0");
+	    xmlSetProp (frame->tree, "id", "index");
+	    xmlDocSetRootElement (priv->toc_doc, frame->tree);
+
+	    pop_stack_frame (pager);
+
+	    gmenu_tree_unref (priv->libmenu_tree);
+	    priv->libmenu_tree = NULL;
+
+
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("\n%ld elapsed (exit process_libmenu_node (%ld))\n", ms, ((glong)ms - ms_start) % 1000000);
+}
+
+	    return FALSE;
+	}
+    }
+
+    item = frame->iterator->data;
+
+    switch (gmenu_tree_item_get_type (item)) {
+    case GMENU_TREE_ITEM_DIRECTORY: 
+	{
+	    g_print ("directory");
+	    push_stack_frame (pager, GMENU_TREE_DIRECTORY (item));
+	}
+	break;
+    case GMENU_TREE_ITEM_ENTRY:
+	{
+	    GMenuTreeEntry *entry = GMENU_TREE_ENTRY (item);
+	    const char     *path = gmenu_tree_entry_get_desktop_file_path (entry);
+	    const char     *desktop_entry_group;
+	    char           *docpath = NULL;
+	    GKeyFile       *key_file;
+
+	    key_file = g_key_file_new ();
+
+	    g_print ("entry (%s)", path);
+
+	    if (!g_key_file_load_from_file (key_file, path, 0, NULL)) {
+		g_key_file_free (key_file);
+		break;
+	    }
+
+	    if (g_key_file_has_group (key_file, DESKTOP_ENTRY_GROUP)) {
+		desktop_entry_group = DESKTOP_ENTRY_GROUP;
+	    } else {
+		if (g_key_file_has_group (key_file, KDE_DESKTOP_ENTRY_GROUP)) {
+		    desktop_entry_group = KDE_DESKTOP_ENTRY_GROUP;
+		} else {
+		    g_key_file_free (key_file);
+		    break;
+		}
+	    }
+
+	    docpath = g_key_file_get_string (key_file, desktop_entry_group, "DocPath", NULL);
+
+	    if (docpath) {
+		xmlNode *new = xmlNewChild (frame->tree, NULL, "doc", NULL);
+		xmlNewNsProp (new, NULL, "href", docpath);
+		xmlNewTextChild (new, NULL, "title", gmenu_tree_entry_get_name (entry));
+		xmlNewTextChild (new, NULL, "description", gmenu_tree_entry_get_comment (entry));
+		set_icon (new, gmenu_tree_entry_get_icon (entry));
+
+		frame->non_empty = TRUE;
+
+		g_free (docpath);
+	    }
+	}
+	break;
+    default:
+	/* Ignore */
+	break;
+    }
+
+
+    frame->iterator = frame->iterator->next;
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("\n%ld elapsed (exit process_libmenu_node (%ld))\n", ms, ((glong)ms - ms_start) % 1000000);
+}
+    return TRUE;
+}
+
+#if 0
+static xmlNode *
+build_menu_dir_xml (GMenuTreeDirectory *dir)
+{
+    gboolean non_empty = FALSE;
+    GSList *items;
+    xmlNode *tree;
+
+    tree = xmlNewNode (NULL, "toc");
+    xmlSetProp (tree, "id", gmenu_tree_directory_get_menu_id (dir));
+    xmlNewTextChild (tree, NULL, "title", gmenu_tree_directory_get_name (dir));
+
+    set_icon (tree, gmenu_tree_directory_get_icon (dir));
+
+    for (items = gmenu_tree_directory_get_contents (dir); items; items = items->next) {
+	GMenuTreeItem *item = items->data;
+	switch (gmenu_tree_item_get_type (item)) {
+	case GMENU_TREE_ITEM_DIRECTORY: 
+	    {
+		xmlNode *child;
+
+		child = build_menu_dir_xml (GMENU_TREE_DIRECTORY (item));
+
+		if (child) {
+		    xmlAddChild (tree, child);
+		    non_empty = TRUE;
+		}
+	    }
+	    break;
+	case GMENU_TREE_ITEM_ENTRY:
+	    {
+		GMenuTreeEntry *entry = GMENU_TREE_ENTRY (item);
+		const char     *path = gmenu_tree_entry_get_desktop_file_path (entry);
+		const char     *desktop_entry_group;
+		char           *docpath = NULL;
+		GKeyFile       *key_file;
+
+		key_file = g_key_file_new ();
+
+		if (!g_key_file_load_from_file (key_file, path, 0, NULL)) {
+		    g_key_file_free (key_file);
+		    break;
+		}
+
+		if (g_key_file_has_group (key_file, DESKTOP_ENTRY_GROUP)) {
+		    desktop_entry_group = DESKTOP_ENTRY_GROUP;
+		} else {
+		    if (g_key_file_has_group (key_file, KDE_DESKTOP_ENTRY_GROUP)) {
+			desktop_entry_group = KDE_DESKTOP_ENTRY_GROUP;
+		    } else {
+			g_key_file_free (key_file);
+			break;
+		    }
+		}
+
+		docpath = g_key_file_get_string (key_file, desktop_entry_group, "DocPath", NULL);
+
+		if (docpath) {
+		    xmlNode *new = xmlNewChild (tree, NULL, "doc", NULL);
+		    xmlNewNsProp (new, NULL, "href", docpath);
+		    xmlNewTextChild (new, NULL, "title", gmenu_tree_entry_get_name (entry));
+		    xmlNewTextChild (new, NULL, "description", gmenu_tree_entry_get_comment (entry));
+		    set_icon (new, gmenu_tree_entry_get_icon (entry));
+
+		    non_empty = TRUE;
+
+		    g_free (docpath);
+		}
+	    }
+	    break;
+	default:
+	    /* Ignore */
+	    break;
+	}
+    }
+    if (!non_empty) {
+	xmlFreeNode (tree);
+	tree = NULL;
+    }
+    return tree;
+}
+#endif
+
+static gboolean
+process_libmenu (YelpTocPager *pager)
+{
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+
+    timer = g_timer_new ();
+    g_timer_start(timer);
+
+    priv->libmenu_tree = gmenu_tree_lookup ("applications.menu",
+					     GMENU_TREE_FLAGS_NONE);
+
+    push_stack_frame (pager, gmenu_tree_get_root_directory (priv->libmenu_tree));
+
+#if 0
+    priv->toc_doc = xmlNewDoc ("1.0");
+
+    root = build_menu_dir_xml (gmenu_tree_get_root_directory (tree));
+
+    xmlSetProp (root, "id", "index");
+
+    xmlDocSetRootElement (priv->toc_doc, root);
+
+
+    gmenu_tree_unref (tree);
+#endif
+
+    return FALSE;
+}
+
+#ifdef ENABLE_SCROLLKEEPER
+
 /** process_read_scrollkeeper *************************************************/
 
 static void
@@ -559,6 +880,7 @@ process_omf_pending (YelpTocPager *pager
     else
 	return FALSE;
 }
+#endif
 
 #ifdef ENABLE_MAN
 static gboolean
@@ -750,6 +1072,7 @@ process_info_pending (YelpTocPager *page
 }
 #endif /* ENABLE_INFO */
 
+#ifdef ENABLE_SCROLLKEEPER
 static gboolean
 process_read_menu (YelpTocPager *pager)
 {
@@ -794,17 +1117,7 @@ process_read_menu (YelpTocPager *pager)
 	xml_trim_titles (node);
 
 	icon = xmlGetProp (node, "icon");
-	if (icon) {
-	    GtkIconInfo *info;
-	    GtkIconTheme *theme = 
-		(GtkIconTheme *) yelp_settings_get_icon_theme ();
-	    info = gtk_icon_theme_lookup_icon (theme, icon, 48, 0);
-	    if (info) {
-		xmlNodePtr new = xmlNewChild (node, NULL, "icon", NULL);
-		xmlNewNsProp (new, NULL, "file", gtk_icon_info_get_filename (info));
-		gtk_icon_info_free (info);
-	    }
-	}
+	set_icon (node, icon);
 	xmlFree (icon);
 
     }
@@ -862,19 +1175,28 @@ process_read_menu (YelpTocPager *pager)
 
     return FALSE;
 }
+#endif
 
 static gboolean
 process_xslt (YelpTocPager *pager)
 {
     GError *error = NULL;
-    xmlDocPtr outdoc;
+    xmlDocPtr outdoc = NULL;
     YelpTocPagerPriv *priv = pager->priv;
     gchar **params;
     gint  params_i = 0;
-    gint  params_max = 10;
+    gint  params_max = 12;
     GtkIconInfo *info;
     GtkIconTheme *theme = (GtkIconTheme *) yelp_settings_get_icon_theme ();
 
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed\n", ms);
+}
+
+
+    d(xmlDocFormatDump(stdout, priv->toc_doc, 1));
+
     priv->stylesheet = xsltParseStylesheetFile (TOC_STYLESHEET);
     if (!priv->stylesheet) {
 	g_set_error (&error, YELP_ERROR, YELP_ERROR_PROC,
@@ -886,6 +1208,10 @@ process_xslt (YelpTocPager *pager)
 	goto done;
     }
 
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed\n", ms);
+}
     priv->transformContext = xsltNewTransformContext (priv->stylesheet,
 						      priv->toc_doc);
     priv->transformContext->_private = pager;
@@ -897,11 +1223,15 @@ process_xslt (YelpTocPager *pager)
     params = g_new0 (gchar *, params_max);
     yelp_settings_params (&params, &params_i, &params_max);
 
-    if ((params_i + 10) >= params_max - 1) {
-	params_max += 10;
+    if ((params_i + 12) >= params_max - 1) {
+	params_max += 12;
 	params = g_renew (gchar *, params, params_max);
     }
 
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed\n", ms);
+}
     info = gtk_icon_theme_lookup_icon (theme, "yelp-icon-big", 192, 0);
     if (info) {
 	params[params_i++] = "help_icon";
@@ -913,8 +1243,15 @@ process_xslt (YelpTocPager *pager)
 	gtk_icon_info_free (info);
     }
 
+    params[params_i++] = "yelp.javascript";
+    params[params_i++] = g_strdup_printf ("\"%s\"", DATADIR "/yelp/yelp.js");
+
     params[params_i++] = NULL;
 
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed\n", ms);
+}
     outdoc = xsltApplyStylesheetUser (priv->stylesheet,
 				      priv->toc_doc,
 				      (const gchar **)params, NULL, NULL,
@@ -941,9 +1278,15 @@ process_xslt (YelpTocPager *pager)
 	priv->transformContext = NULL;
     }
 
+{    gulong ms;
+	    g_timer_elapsed (timer, &ms);
+	    g_print ("%ld elapsed\n", ms);
+}
+
     return FALSE;
 }
 
+#ifdef ENABLE_SCROLLKEEPER
 static void
 toc_add_doc_info (YelpTocPager *pager, YelpDocInfo *doc_info)
 {
@@ -1000,6 +1343,8 @@ toc_remove_doc_info (YelpTocPager *pager
 #endif
 }
 
+#endif
+
 static void
 xslt_yelp_document (xsltTransformContextPtr ctxt,
 		    xmlNodePtr              node,
@@ -1120,6 +1465,7 @@ xslt_yelp_document (xsltTransformContext
 	xsltFreeStylesheet (style);
 }
 
+#ifdef ENABLE_SCROLLKEEPER
 static void
 xml_trim_titles (xmlNodePtr node)
 {
@@ -1169,3 +1515,4 @@ xml_trim_titles (xmlNodePtr node)
     }
     xmlFree (keep_lang);
 }
+#endif
Index: src/yelp-uri.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-uri.c,v
retrieving revision 1.22
diff -u -p -r1.22 yelp-uri.c
--- src/yelp-uri.c	22 Feb 2005 23:44:28 -0000	1.22
+++ src/yelp-uri.c	6 Jul 2005 19:30:56 -0000
@@ -38,6 +38,7 @@ static gboolean      uri_parse_uri      
 static void          uri_parse_toc_uri             (YelpURI      *uri);
 static void          uri_parse_man_uri             (YelpURI      *uri);
 static void          uri_parse_ghelp_uri           (YelpURI      *uri);
+static void          uri_parse_help_uri           (YelpURI      *uri);
 static gchar *       uri_locate_file               (gchar        *path,
 						    gchar        *file);
 static gchar *       uri_locate_file_lang          (gchar        *path,
@@ -97,6 +98,7 @@ uri_set_resource_type (YelpURI *uri)
 	return;
     }
 
+    /* if (scheme != "file") */
     if (strcmp (gnome_vfs_uri_get_scheme (uri->uri), "file")) {
 	uri->resource_type = YELP_URI_TYPE_EXTERNAL;
 	return;
@@ -158,6 +160,10 @@ uri_parse_uri (YelpURI *uri)
 	uri_parse_ghelp_uri (uri);
 	return TRUE;
     }
+    if (!strncmp (uri->src_uri, "help:", 5)) {
+	uri_parse_help_uri (uri);
+	return TRUE;
+    }
     else if (!strncmp (uri->src_uri, "man:", 4)) {
 	uri_parse_man_uri (uri);
 	return TRUE;
@@ -232,7 +238,7 @@ uri_parse_ghelp_uri (YelpURI *uri)
     else
 	goto done;
 
-    if (path[0] && path[0] == '/') {
+    if (path[0] == '/') {
 	gchar *str = g_strconcat ("file:", path, NULL);
 
 	if ((c = strchr (str, '?')))
@@ -301,6 +307,127 @@ uri_parse_ghelp_uri (YelpURI *uri)
 
     if (!uri)
 	g_warning ("Couldn't resolve ghelp URI: %s", uri->src_uri);
+}
+
+static gboolean
+help_uri_check_file (YelpURI *uri, gchar *filename, gchar *reference) {
+    g_print ("Checking %s\n", filename);
+    if (g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+	gchar *full_uri;
+	if (reference) {
+	    full_uri = g_strconcat ("file://", filename, "#", reference, NULL);
+	} else {
+	    full_uri = g_strconcat ("file://", filename, NULL);
+	}
+
+	uri->uri = gnome_vfs_uri_new (full_uri);
+	uri_set_resource_type (uri);
+
+	g_free (full_uri);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+static gboolean
+help_uri_check_dir (YelpURI *uri, gchar *path, gchar *identifier, gchar *reference)
+{
+    gboolean result;
+
+    gchar *full_path;
+    gchar *full_identifier;
+
+    result = help_uri_check_file (uri, path, reference);
+    if (result)
+	return TRUE;
+
+    full_path = g_build_filename (path, "index.docbook", NULL);
+    result = help_uri_check_file (uri, full_path, reference);
+    g_free (full_path);
+    if (result)
+	return TRUE;
+
+    full_identifier = g_strconcat (identifier, ".xml", NULL);
+    full_path = g_build_filename (path, full_identifier, NULL);
+    result = help_uri_check_file (uri, full_path, reference);
+    g_free (full_path);
+    g_free (full_identifier);
+    if (result)
+	return TRUE;
+}
+
+static gboolean
+help_uri_search (YelpURI *uri, gchar *path, gchar *identifier)
+{
+    gboolean result;
+
+    result = help_uri_check_dir (uri, path, identifier, NULL);
+    if (result)
+	return TRUE;
+
+    if (strlen (path) > 5 && strcmp (path + strlen (path) - 5, ".html")) {
+	gchar *slash = strrchr (path, '/');
+	if (slash != NULL) {
+	    gchar *shortened = g_strndup (path, slash - path);
+	    gchar *reference = g_strndup (slash + 1, strlen (slash + 1) - 5);
+	    result = help_uri_check_dir (uri, shortened, identifier);
+	    g_free (reference);
+	    g_free (shortened);
+	    if (result)
+		return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+static void
+uri_parse_help_uri (YelpURI *uri)
+{
+    GSList *locations = NULL;
+    GSList *node;
+    gchar  *path, *c;
+    gchar  *doc_id    = NULL;
+    gchar  *file_name = NULL;
+    gchar  *link_id   = NULL;
+    const gchar * const * langs;
+    gboolean result;
+
+    GnomeProgram *program = gnome_program_get ();
+
+    if ((path = strchr(uri->src_uri, ':')))
+	path++;
+    else
+	goto done;
+
+    while (*path == '/')
+	path++;
+
+    if ((slash = strchr(path, '/'))) {
+	file_name = g_strdup (slash + 1);
+	path = g_strndup (path, slash - path);
+    } else {
+	path = g_strdup (path);
+	file_name = g_strdup ("");
+    }
+
+    langs = g_get_language_names ();
+
+    for (i = 0; langs[i] != NULL; i++) {
+	gnome_path = g_strdup_printf (DATADIR "/gnome/help/%s/%s/%s", path, lang, file_name);
+	result = help_uri_search (uri, gnome_path, path);
+	g_free (gnome_path);
+	if (result)
+	    return;
+    }
+
+    gnome_path = g_strdup_printf (DATADIR "/gnome/help/%s/C/%s", path, file_name);
+    result = help_uri_search (uri, gnome_path, path);
+    g_free (gnome_path);
+    if (result)
+	return;
+
+    return;
 }
 
 static gchar *
Index: src/yelp-utils.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-utils.c,v
retrieving revision 1.25
diff -u -p -r1.25 yelp-utils.c
--- src/yelp-utils.c	22 Feb 2005 23:44:28 -0000	1.25
+++ src/yelp-utils.c	6 Jul 2005 19:30:56 -0000
@@ -37,7 +37,7 @@
 #ifdef YELP_DEBUG
 #define d(x) x
 #else
-#define d(x)
+#define d(x) x
 #endif
 
 GHashTable *doc_info_table;
@@ -68,6 +68,7 @@ struct _YelpDocInfo {
 
 static YelpDocType  get_doc_type       (gchar   *uri);
 static gchar *      convert_ghelp_uri  (gchar   *uri);
+static gchar *      convert_help_uri   (gchar   *uri);
 
 static gchar *      convert_man_uri    (gchar   *uri);
 static gchar *      convert_info_uri   (gchar   *uri);
@@ -106,6 +107,12 @@ yelp_doc_info_new (const gchar *uri)
 	    doc_type = get_doc_type (doc_uri);
 	uri_type = YELP_URI_TYPE_GHELP;
     }
+    else if (g_str_has_prefix (full_uri, "help:")) {
+	doc_uri  = convert_help_uri (full_uri);
+	if (doc_uri)
+	    doc_type = get_doc_type (doc_uri);
+	uri_type = YELP_URI_TYPE_HELP;
+    }
     else if (g_str_has_prefix (full_uri, "man:")) {
 	doc_uri  = convert_man_uri (full_uri);
 	doc_type = YELP_DOC_TYPE_MAN;
@@ -121,6 +128,11 @@ yelp_doc_info_new (const gchar *uri)
 	doc_type = YELP_DOC_TYPE_TOC;
 	uri_type = YELP_URI_TYPE_TOC;
     }
+    else if (g_str_has_prefix (full_uri, "x-yelp-search:")) {
+	doc_uri = g_strdup (full_uri);
+	doc_type = YELP_DOC_TYPE_SEARCH;
+	uri_type = YELP_URI_TYPE_SEARCH;
+    }
     else {
 	doc_uri = g_strdup (uri);
 	doc_type = YELP_DOC_TYPE_EXTERNAL;
@@ -562,6 +574,133 @@ yelp_doc_info_add_uri (YelpDocInfo *doc_
 
 /******************************************************************************/
 /** Convert fancy URIs to file URIs *******************************************/
+
+static gchar *
+help_uri_check_file (gchar *filename, gchar *reference) {
+    g_print ("Checking %s\n", filename);
+    if (g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+	gchar *full_uri;
+	if (reference) {
+	    full_uri = g_strconcat ("file://", filename, "#", reference, NULL);
+	} else {
+	    full_uri = g_strconcat ("file://", filename, NULL);
+	}
+
+	return full_uri;
+    }
+
+    return NULL;
+}
+
+static gchar *
+help_uri_check_dir (gchar *path, gchar *identifier, gchar *reference)
+{
+    gchar *result;
+
+    gchar *full_path;
+    gchar *full_identifier;
+
+    result = help_uri_check_file (path, reference);
+    if (result)
+	return result;
+
+    full_path = g_build_filename (path, "index.docbook", NULL);
+    result = help_uri_check_file (full_path, reference);
+    g_free (full_path);
+    if (result)
+	return result;
+
+    full_identifier = g_strconcat (identifier, ".xml", NULL);
+    full_path = g_build_filename (path, full_identifier, NULL);
+    result = help_uri_check_file (full_path, reference);
+    g_free (full_path);
+    g_free (full_identifier);
+    if (result)
+	return result;
+
+    return NULL;
+}
+
+static gchar *
+help_uri_search (gchar *path, gchar *identifier)
+{
+    gchar *result;
+
+    result = help_uri_check_dir (path, identifier, NULL);
+    if (result)
+	return result;
+
+    if (strlen (path) > 5 && strcmp (path + strlen (path) - 5, ".html")) {
+	gchar *slash = strrchr (path, '/');
+	if (slash != NULL) {
+	    gchar *shortened = g_strndup (path, slash - path);
+	    gchar *reference = g_strndup (slash + 1, strlen (slash + 1) - 5);
+	    result = help_uri_check_dir (shortened, identifier, reference);
+	    g_free (reference);
+	    g_free (shortened);
+	    if (result)
+		return result;
+	}
+    }
+    return NULL;
+}
+
+static gchar *
+convert_help_uri (gchar *uri)
+{
+    gchar  *path;
+    gchar  *file_name = NULL;
+    const gchar * const * langs;
+    gchar *result;
+    gchar *gnome_path, *slash;
+    int i;
+
+    if ((path = strchr(uri, ':')))
+	path++;
+    else
+	return NULL;
+
+    while (*path == '/')
+	path++;
+
+    if ((slash = strchr(path, '/'))) {
+	file_name = g_strdup (slash + 1);
+	path = g_strndup (path, slash - path);
+    } else {
+	path = g_strdup (path);
+	file_name = g_strdup ("");
+    }
+
+    langs = g_get_language_names ();
+
+    for (i = 0; langs[i] != NULL; i++) {
+	gnome_path = g_strdup_printf (DATADIR "/gnome/help/%s/%s/%s", path, langs[i], file_name);
+	result = help_uri_search (gnome_path, path);
+	g_free (gnome_path);
+	if (result)
+	    return result;
+
+	gnome_path = g_strdup_printf ("/opt/gnome/share/gnome/help/%s/%s/%s", path, langs[i], file_name);
+	result = help_uri_search (gnome_path, path);
+	g_free (gnome_path);
+	if (result)
+	    return result;
+    }
+
+    gnome_path = g_strdup_printf (DATADIR "/gnome/help/%s/C/%s", path, file_name);
+    result = help_uri_search (gnome_path, path);
+    g_free (gnome_path);
+    if (result)
+	return result;
+
+    gnome_path = g_strdup_printf ("/opt/gnome/share/gnome/help/%s/C/%s", path, file_name);
+    result = help_uri_search (gnome_path, path);
+    g_free (gnome_path);
+    if (result)
+	return result;
+
+    return NULL;
+}
 
 static gchar *
 locate_file_lang (gchar *path, gchar *file, const gchar *lang)
Index: src/yelp-utils.h
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-utils.h,v
retrieving revision 1.11
diff -u -p -r1.11 yelp-utils.h
--- src/yelp-utils.h	22 Feb 2005 19:17:01 -0000	1.11
+++ src/yelp-utils.h	6 Jul 2005 19:30:56 -0000
@@ -37,7 +37,8 @@ typedef enum {
     YELP_DOC_TYPE_MAN,
     YELP_DOC_TYPE_INFO,
     YELP_DOC_TYPE_TOC,
-    YELP_DOC_TYPE_EXTERNAL
+    YELP_DOC_TYPE_EXTERNAL,
+    YELP_DOC_TYPE_SEARCH
 } YelpDocType;
 
 static gchar *mandirs[] = {
@@ -65,20 +66,20 @@ typedef enum {
     YELP_URI_TYPE_INFO     = 1 << 3,
     YELP_URI_TYPE_TOC      = 1 << 4,
     YELP_URI_TYPE_EXTERNAL = 1 << 5,
+    YELP_URI_TYPE_HELP     = 1 << 6,
+    YELP_URI_TYPE_SEARCH   = 1 << 7,
 
     YELP_URI_TYPE_NO_FILE =
       YELP_URI_TYPE_GHELP   |
       YELP_URI_TYPE_MAN     |
       YELP_URI_TYPE_INFO    |
       YELP_URI_TYPE_TOC     |
-      YELP_URI_TYPE_EXTERNAL,
+      YELP_URI_TYPE_EXTERNAL|
+      YELP_URI_TYPE_HELP    |
+      YELP_URI_TYPE_SEARCH,
     YELP_URI_TYPE_ANY =
       YELP_URI_TYPE_FILE    |
-      YELP_URI_TYPE_GHELP   |
-      YELP_URI_TYPE_MAN     |
-      YELP_URI_TYPE_INFO    |
-      YELP_URI_TYPE_TOC     |
-      YELP_URI_TYPE_EXTERNAL
+      YELP_URI_TYPE_NO_FILE
 } YelpURIType;
 
 #include "yelp-pager.h"
Index: src/yelp-window.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-window.c,v
retrieving revision 1.172
diff -u -p -r1.172 yelp-window.c
--- src/yelp-window.c	16 May 2005 21:02:33 -0000	1.172
+++ src/yelp-window.c	6 Jul 2005 19:30:56 -0000
@@ -41,12 +41,15 @@
 
 #include "yelp-bookmarks.h"
 #include "yelp-db-pager.h"
+#include "yelp-search-pager.h"
+#include "yelp-db-print-pager.h"
 #include "yelp-error.h"
 #include "yelp-html.h"
 #include "yelp-pager.h"
 #include "yelp-settings.h"
 #include "yelp-toc-pager.h"
 #include "yelp-window.h"
+#include "gtkentryaction.h"
 
 #ifdef ENABLE_MAN
 #include "yelp-man-pager.h"
@@ -66,7 +69,7 @@
 #define YELP_CONFIG_WIDTH_DEFAULT  "600"
 #define YELP_CONFIG_HEIGHT_DEFAULT "420"
 
-#define BUFFER_SIZE 16384
+#define BUFFER_SIZE 4096
 
 typedef struct {
     YelpWindow *window;
@@ -155,6 +158,8 @@ static void    window_add_widget        
 					 GtkWidget    *vbox);
 static void    window_new_window_cb     (GtkAction *action, YelpWindow *window);
 static void    window_about_document_cb (GtkAction *action, YelpWindow *window);
+static void    window_print_document_cb (GtkAction *action, YelpWindow *window);
+static void    window_print_page_cb    (GtkAction *action, YelpWindow *window);
 static void    window_open_location_cb  (GtkAction *action, YelpWindow *window);
 static void    window_close_window_cb   (GtkAction *action, YelpWindow *window);
 static void    window_copy_cb           (GtkAction *action, YelpWindow *window);
@@ -294,6 +299,16 @@ static const GtkActionEntry entries[] = 
       "<Control>N",
       NULL,
       G_CALLBACK (window_new_window_cb) },
+    { "PrintDocument", NULL,
+      N_("Print This Document"),
+      NULL,
+      NULL,
+      G_CALLBACK (window_print_document_cb) },
+    { "PrintPage", NULL,
+      N_("Print This Page"),
+      NULL,
+      NULL,
+      G_CALLBACK (window_print_page_cb) },
     { "AboutDocument", NULL,
       N_("About This Document"),
       NULL,
@@ -801,6 +816,7 @@ window_do_load (YelpWindow  *window,
 
     case YELP_DOC_TYPE_DOCBOOK_XML:
     case YELP_DOC_TYPE_TOC:
+    case YELP_DOC_TYPE_SEARCH:
 	handled = window_do_load_pager (window, doc_info, frag_id);
 	break;
     case YELP_DOC_TYPE_DOCBOOK_SGML:
@@ -882,6 +898,28 @@ window_error (YelpWindow *window, GError
     gtk_widget_destroy (dialog);
 }
 
+static char *
+encode_search_uri (const char *search_terms)
+{
+    return g_strdup_printf ("x-yelp-search:%s", search_terms);
+}
+
+static void
+search_activated (GtkAction *action,
+		  YelpWindow *window)
+{
+    const char *search_terms;
+    char *uri;
+
+    search_terms = gtk_entry_action_get_text (GTK_ENTRY_ACTION (action));
+
+    uri = encode_search_uri (search_terms);
+
+    yelp_window_load (window, uri);
+
+    g_free (uri);
+}
+
 static void
 window_populate (YelpWindow *window)
 {
@@ -903,6 +941,14 @@ window_populate (YelpWindow *window)
     gtk_action_group_add_actions (priv->action_group,
 				  entries, G_N_ELEMENTS (entries),
 				  window);
+
+    action = gtk_entry_action_new ("Search",
+				   _("Search"),
+				   _("Search for other documentation"),
+				   NULL);
+    g_signal_connect (G_OBJECT (action), "activate",
+		      G_CALLBACK (search_activated), window);
+    gtk_action_group_add_action (priv->action_group, action);
     priv->ui_manager = gtk_ui_manager_new ();
     gtk_ui_manager_insert_action_group (priv->ui_manager, priv->action_group, 0);
 
@@ -1147,6 +1193,8 @@ window_do_load_pager (YelpWindow  *windo
 	case YELP_DOC_TYPE_TOC:
 	    pager = YELP_PAGER (yelp_toc_pager_get ());
 	    break;
+	case YELP_DOC_TYPE_SEARCH:
+	    pager = YELP_PAGER (yelp_search_pager_get (doc_info));
 	default:
 	    break;
 	}
@@ -1264,61 +1312,45 @@ window_do_load_pager (YelpWindow  *windo
 }
 
 static gboolean
-window_do_load_html (YelpWindow    *window,
-		     YelpDocInfo   *doc_info,
-		     gchar         *frag_id)
+load_html (YelpHtml      *html_view,
+	   YelpDocInfo   *doc_info,
+	   gchar         *frag_id,
+	   GError       **error)
 {
-    YelpWindowPriv  *priv;
     GnomeVFSHandle  *handle;
     GnomeVFSResult   result;
     GnomeVFSFileSize n;
     gchar            buffer[BUFFER_SIZE];
-    GtkAction       *action;
 
     gboolean  handled = TRUE;
     gchar    *uri;
 
-    g_return_val_if_fail (YELP_IS_WINDOW (window), FALSE);
+    g_return_val_if_fail (YELP_IS_HTML (html_view), FALSE);
     g_return_val_if_fail (doc_info != NULL, FALSE);
 
-    priv = window->priv;
-
     uri = yelp_doc_info_get_uri (doc_info, frag_id, YELP_URI_TYPE_FILE);
 
-    window_set_sections (window, NULL);
-
-    action = gtk_action_group_get_action (priv->action_group, "GoPrevious");
-    if (action)
-	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
-    action = gtk_action_group_get_action (priv->action_group, "GoNext");
-    if (action)
-	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
-    action = gtk_action_group_get_action (priv->action_group, "GoContents");
-    if (action)
-	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
-
     result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
 
     if (result != GNOME_VFS_OK) {
-	GError *error = NULL;
-	g_set_error (&error, YELP_ERROR, YELP_ERROR_IO,
-		     _("The file â??%sâ?? could not be read.  This file might "
-		       "be missing, or you might not have permissions to "
-		       "read it."),
-		     uri);
-	window_error (window, error, TRUE);
+	if (error)
+	    g_set_error (error, YELP_ERROR, YELP_ERROR_IO,
+			 _("The file â??%sâ?? could not be read.  This file might "
+			   "be missing, or you might not have permissions to "
+			   "read it."),
+			 uri);
 	handled = FALSE;
 	goto done;
     }
 
-    yelp_html_set_base_uri (priv->html_view, uri);
+    yelp_html_set_base_uri (html_view, uri);
 
     switch (yelp_doc_info_get_type (doc_info)) {
     case YELP_DOC_TYPE_HTML:
-	yelp_html_open_stream (priv->html_view, "text/html");
+	yelp_html_open_stream (html_view, "text/html");
 	break;
     case YELP_DOC_TYPE_XHTML:
-	yelp_html_open_stream (priv->html_view, "application/xhtml+xml");
+	yelp_html_open_stream (html_view, "application/xhtml+xml");
 	break;
     default:
 	g_assert_not_reached ();
@@ -1326,10 +1358,10 @@ window_do_load_html (YelpWindow    *wind
 
     while ((result = gnome_vfs_read
 	    (handle, buffer, BUFFER_SIZE, &n)) == GNOME_VFS_OK) {
-	yelp_html_write (priv->html_view, buffer, n);
+	yelp_html_write (html_view, buffer, n);
     }
 
-    yelp_html_close (priv->html_view);
+    yelp_html_close (html_view);
 
  done:
     if (handle)
@@ -1340,6 +1372,43 @@ window_do_load_html (YelpWindow    *wind
     return handled;
 }
 
+static gboolean
+window_do_load_html (YelpWindow    *window,
+		     YelpDocInfo   *doc_info,
+		     gchar         *frag_id)
+{
+    YelpWindowPriv  *priv;
+    GError          *error = NULL;
+    gboolean         handled;
+    GtkAction       *action;
+
+    g_return_val_if_fail (YELP_IS_WINDOW (window), FALSE);
+
+    priv = window->priv;
+
+    window_set_sections (window, NULL);
+
+    action = gtk_action_group_get_action (priv->action_group, "GoPrevious");
+    if (action)
+	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
+    action = gtk_action_group_get_action (priv->action_group, "GoNext");
+    if (action)
+	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
+    action = gtk_action_group_get_action (priv->action_group, "GoContents");
+    if (action)
+	g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
+
+    handled = load_html (priv->html_view,
+			 doc_info,
+			 frag_id,
+			 &error);
+
+    if (error)
+	window_error (window, error, TRUE);
+
+    return handled;
+}
+
 static void
 window_set_loading (YelpWindow *window)
 {
@@ -1816,6 +1885,170 @@ window_new_window_cb (GtkAction *action,
     g_return_if_fail (YELP_IS_WINDOW (window));
 
     g_signal_emit (window, signals[NEW_WINDOW_REQUESTED], 0, NULL);
+}
+
+typedef struct {
+    gulong page_handler;
+    gulong error_handler;
+    gulong cancel_handler;
+    gulong finish_handler;
+    YelpPager *pager;
+} PrintStruct;
+
+static void
+print_disconnect (PrintStruct *data)
+{
+    if (data->page_handler) {
+	g_signal_handler_disconnect (data->pager,
+				     data->page_handler);
+	data->page_handler = 0;
+    }
+    if (data->error_handler) {
+	g_signal_handler_disconnect (data->pager,
+				     data->error_handler);
+	data->error_handler = 0;
+    }
+    if (data->cancel_handler) {
+	g_signal_handler_disconnect (data->pager,
+				     data->cancel_handler);
+	data->cancel_handler = 0;
+    }
+    if (data->finish_handler) {
+	g_signal_handler_disconnect (data->pager,
+				     data->finish_handler);
+	data->finish_handler = 0;
+    }
+    if (data) {
+	if (data->pager)
+	    g_object_unref (data->pager);
+    }
+    g_free (data);
+}
+
+static void
+print_pager_page_cb (YelpPager *pager,
+		     gchar     *page_id,
+		     gpointer   user_data)
+{
+    PrintStruct *data = user_data;
+    YelpPage    *page;
+
+    d (g_print ("print_pager_page_cb\n"));
+    d (g_print ("  page_id=\"%s\"\n", page_id));
+
+
+    page = (YelpPage *) yelp_pager_get_page (pager, page_id);
+
+    if (page) {
+	YelpHtml *html;
+	GtkWidget *gtk_window;
+	int length, offset;
+
+	d(g_print (page->contents));
+
+	gtk_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	html = yelp_html_new ();
+	gtk_container_add (GTK_CONTAINER (gtk_window), GTK_WIDGET (html));
+	gtk_widget_realize (gtk_window);
+	gtk_widget_realize (GTK_WIDGET (html));
+
+
+	yelp_html_set_base_uri (html, page->page_id);
+	yelp_html_open_stream (html, "application/xhtml+xml");
+	for (length = strlen (page->contents), offset = 0; length > 0; length -= BUFFER_SIZE, offset += BUFFER_SIZE) {
+	    g_print ("data: %.*s\n", MIN (length, BUFFER_SIZE), page->contents + offset);
+	    yelp_html_write (html, page->contents + offset, MIN (length, BUFFER_SIZE));
+	}
+	yelp_html_close (html);
+
+	yelp_html_print (html);
+
+	print_disconnect (data);
+
+	/* This needs to be done at some point, but we need to wait until printing is done. */
+	/* gtk_widget_destroy (gtk_window); */
+    }
+}
+
+static void
+print_pager_error_cb (YelpPager   *pager,
+		      gpointer     user_data)
+{
+    PrintStruct *data = user_data;
+    /*     GError *error = yelp_pager_get_error (pager);*/
+
+    d (g_print ("print_pager_error_cb\n"));
+
+    print_disconnect (data);
+}
+
+static void
+print_pager_cancel_cb (YelpPager   *pager,
+		       gpointer     user_data)
+{
+    PrintStruct *data = user_data;
+    d (g_print ("print_pager_cancel_cb\n"));
+
+    print_disconnect (data);
+}
+
+static void
+print_pager_finish_cb (YelpPager   *pager,
+		       gpointer     user_data)
+{
+    PrintStruct *data = user_data;
+
+    d (g_print ("print_pager_finish_cb\n"));
+
+    print_disconnect (data);
+}
+
+static void
+window_print_document_cb (GtkAction *action, YelpWindow *window)
+{
+    PrintStruct *data;
+    YelpPager *pager;
+
+    if (!window->priv->current_doc)
+	return;
+
+    pager = yelp_db_print_pager_new (window->priv->current_doc);
+
+    if (!pager) {
+	return;
+    }
+
+    data = g_new0 (PrintStruct, 1);
+    data->pager = pager;
+
+    data->page_handler =
+	g_signal_connect (data->pager,
+			  "page",
+			  G_CALLBACK (print_pager_page_cb),
+			  data);
+    data->error_handler =
+	g_signal_connect (data->pager,
+			  "error",
+			  G_CALLBACK (print_pager_error_cb),
+			  data);
+    data->cancel_handler =
+	g_signal_connect (data->pager,
+			  "error",
+			  G_CALLBACK (print_pager_cancel_cb),
+			  data);
+    data->finish_handler =
+	g_signal_connect (data->pager,
+			  "finish",
+			  G_CALLBACK (print_pager_finish_cb),
+			  data);
+
+    /* handled = */ yelp_pager_start (data->pager);
+}
+
+static void
+window_print_page_cb (GtkAction *action, YelpWindow *window)
+{
+    yelp_html_print (window->priv->html_view);
 }
 
 static void
Index: stylesheets/Makefile.am
===================================================================
RCS file: /cvs/gnome/yelp/stylesheets/Makefile.am,v
retrieving revision 1.14
diff -u -p -r1.14 Makefile.am
--- stylesheets/Makefile.am	16 May 2005 20:07:37 -0000	1.14
+++ stylesheets/Makefile.am	6 Jul 2005 19:30:56 -0000
@@ -7,6 +7,7 @@ xsl_DATA =		\
 	db-title.xsl	\
 	info2html.xsl	\
 	man2html.xsl	\
+	search2html.xsl	\
 	toc2html.xsl	\
 	yelp-common.xsl
 
Index: stylesheets/search2html.xsl
===================================================================
RCS file: stylesheets/search2html.xsl
diff -N stylesheets/search2html.xsl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stylesheets/search2html.xsl	6 Jul 2005 19:30:56 -0000
@@ -0,0 +1,136 @@
+<?xml version='1.0' encoding='UTF-8'?><!-- -*- indent-tabs-mode: nil -*- -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+                xmlns:yelp="http://www.gnome.org/yelp/ns";
+                xmlns="http://www.w3.org/1999/xhtml";
+                extension-element-prefixes="yelp"
+                version="1.0">
+
+<xsl:param name="help_icon"/>
+<xsl:param name="help_icon_size"/>
+
+<xsl:param name="yelp.javascript"/>
+
+<xsl:param name="yelp.color.fg"/>
+<xsl:param name="yelp.color.bg"/>
+<xsl:param name="yelp.color.anchor"/>
+<xsl:param name="yelp.color.rule"/>
+<xsl:param name="yelp.color.gray.fg"/>
+<xsl:param name="yelp.color.gray.bg"/>
+<xsl:param name="yelp.color.gray.bg.dark1"/>
+<xsl:param name="yelp.color.gray.bg.dark2"/>
+<xsl:param name="yelp.color.gray.bg.dark3"/>
+<xsl:param name="yelp.color.selected.fg"/>
+<xsl:param name="yelp.color.selected.bg"/>
+<xsl:param name="yelp.color.selected.bg.dark1"/>
+<xsl:param name="yelp.color.selected.bg.dark2"/>
+<xsl:param name="yelp.color.selected.bg.dark3"/>
+<xsl:param name="yelp.color.admon.fg"/>
+<xsl:param name="yelp.color.admon.bg"/>
+<xsl:param name="yelp.color.admon.bg.dark1"/>
+<xsl:param name="yelp.color.admon.bg.dark2"/>
+<xsl:param name="yelp.color.admon.bg.dark3"/>
+
+<xsl:template match="search">
+  <yelp:document href="results">
+    <html>
+      <head>
+        <title>
+          <xsl:value-of select="@title"/>
+        </title>
+        <script type="text/javascript">
+          <xsl:attribute name="src">
+            <xsl:value-of select="concat('file://', $yelp.javascript)"/>
+          </xsl:attribute>
+        </script>
+        <style><xsl:text>
+        body {
+          margin: 0px;
+          padding: 0px;
+        }
+        h1 {
+          position: relative;
+          font-size: 1.6em;
+          margin-bottom: 0.4em;
+          margin-top: 12px;
+          padding-top: 0.2em;
+          padding-bottom: 0.2em;
+          -moz-border-radius: 6px;
+          border: solid 1px </xsl:text>
+          <xsl:value-of select="$yelp.color.selected.bg.dark1"/><xsl:text>;
+          background-color: </xsl:text>
+          <xsl:value-of select="$yelp.color.selected.bg"/><xsl:text>;
+          color: </xsl:text>
+          <xsl:value-of select="$yelp.color.selected.fg"/><xsl:text>;
+          margin-left: 12px;
+          padding-left: 12px;
+        }
+        body > div > h1 {
+          padding-left: 204px;
+          margin-right: 12px;
+        }
+        h1 img {
+          position: absolute;
+          top: -6px;
+          right: 18px;
+        }
+        div[class~="body"] { }
+        div[class~="leftbar"] {
+          position: absolute;
+          top: 4em;
+          left: 12px;
+          width: 192px;
+          min-height: 192px;
+          text-align: center;
+          <!-- FIXME: this isn't working -->
+          padding-top: </xsl:text>
+          <xsl:value-of select="$help_icon_size"/><xsl:text> px;
+          background-image: url("</xsl:text>
+          <xsl:value-of select="$help_icon"/><xsl:text>");
+          background-position: </xsl:text>
+          <xsl:value-of select="(192 - $help_icon_size) div 2"/><xsl:text>px 0px;
+          background-repeat: no-repeat;
+          opacity: .3;
+        }
+        div[class~="rightbar"] {
+          margin-left: 12px;
+          padding-bottom: 1em;
+        }
+        body > div > div[class~="rightbar"] {
+          margin-left: 216px;
+          margin-right: 12px;
+        }
+        div[class~="tocs"] + div[class~="docs"] {
+          border-top: solid 1px </xsl:text>
+          <xsl:value-of select="$yelp.color.selected.bg"/><xsl:text>;
+        }
+        ul { font-size: 1em; margin-left: 0em; padding-left: 0em; }
+        li {
+          margin-top: 0.5em;
+          margin-left: 1em;
+          padding-left: 0em;
+          list-style-type: none;
+        }
+        dl { margin-left: 0em; padding-left: 0em; }
+        dt { font-size: 1.2em; margin-top: 1em; }
+        dd { margin-left: 1em; margin-top: 0.5em; }
+        a { text-decoration: none; }
+        a:hover { text-decoration: underline; }
+        </xsl:text></style>
+      </head>
+      <body>
+        <h1>
+          <xsl:value-of select="@title"/>
+        </h1>
+        <xsl:apply-templates select="result">
+            <xsl:sort select="normalize-space(@score)"/>
+            <xsl:sort select="position()"/>
+        </xsl:apply-templates>
+      </body>
+    </html>
+  </yelp:document>
+</xsl:template>
+
+<xsl:template match="result">
+  <p><a href="{ uri}"><xsl:value-of select="@uri"/></a></p>
+</xsl:template>
+</xsl:stylesheet>
Index: stylesheets/toc2html.xsl
===================================================================
RCS file: /cvs/gnome/yelp/stylesheets/toc2html.xsl,v
retrieving revision 1.11
diff -u -p -r1.11 toc2html.xsl
--- stylesheets/toc2html.xsl	11 May 2005 18:19:20 -0000	1.11
+++ stylesheets/toc2html.xsl	6 Jul 2005 19:30:56 -0000
@@ -8,6 +8,8 @@
 <xsl:param name="help_icon"/>
 <xsl:param name="help_icon_size"/>
 
+<xsl:param name="yelp.javascript"/>
+
 <xsl:param name="yelp.color.fg"/>
 <xsl:param name="yelp.color.bg"/>
 <xsl:param name="yelp.color.anchor"/>
@@ -35,18 +37,21 @@
         <title>
           <xsl:value-of select="title[1]"/>
         </title>
+        <script type="text/javascript">
+          <xsl:attribute name="src">
+            <xsl:value-of select="concat('file://', $yelp.javascript)"/>
+          </xsl:attribute>
+        </script>
         <style><xsl:text>
         body {
           margin: 0px;
           padding: 0px;
         }
         h1 {
+          position: relative;
           font-size: 1.6em;
           margin-bottom: 0.4em;
           margin-top: 12px;
-          margin-left: 12px;
-          margin-right: 12px;
-          padding-left: 204px;
           padding-top: 0.2em;
           padding-bottom: 0.2em;
           -moz-border-radius: 6px;
@@ -56,10 +61,16 @@
           <xsl:value-of select="$yelp.color.selected.bg"/><xsl:text>;
           color: </xsl:text>
           <xsl:value-of select="$yelp.color.selected.fg"/><xsl:text>;
+          margin-left: 12px;
+          padding-left: 12px;
+        }
+        body > div > h1 {
+          padding-left: 204px;
+          margin-right: 12px;
         }
         h1 img {
           position: absolute;
-          top: 6px;
+          top: -6px;
           right: 18px;
         }
         div[class~="body"] { }
@@ -81,20 +92,22 @@
           opacity: .3;
         }
         div[class~="rightbar"] {
-          margin-left: 216px;
+          margin-left: 12px;
           padding-bottom: 1em;
+        }
+        body > div > div[class~="rightbar"] {
+          margin-left: 216px;
           margin-right: 12px;
         }
         div[class~="tocs"] + div[class~="docs"] {
           border-top: solid 1px </xsl:text>
           <xsl:value-of select="$yelp.color.selected.bg"/><xsl:text>;
         }
-        ul { margin-left: 0em; padding-left: 0em; }
+        ul { font-size: 1em; margin-left: 0em; padding-left: 0em; }
         li {
           margin-top: 0.5em;
-          margin-left: 0em;
+          margin-left: 1em;
           padding-left: 0em;
-          font-size: 1.2em;
           list-style-type: none;
         }
         dl { margin-left: 0em; padding-left: 0em; }
@@ -105,63 +118,91 @@
         </xsl:text></style>
       </head>
       <body>
+        <div class="leftbar">
+        </div>
         <xsl:apply-templates mode="body.mode" select="."/>
       </body>
     </html>
   </yelp:document>
-  <xsl:apply-templates select="toc[.//doc]"/>
+<!--  <xsl:apply-templates select="toc[.//doc]"/> -->
+</xsl:template>
+
+<xsl:template name="header">
+  <xsl:param name="class"/>
+  <h1 id="{ id}-header" onclick="show_hide ('{ id}');" class="{$class}">
+    <xsl:if test="icon">
+      <img src="{icon/@file}"/>
+    </xsl:if>
+    <xsl:apply-templates select="title[1]/node()"/>
+  </h1>
+</xsl:template>
+
+<xsl:template name="children">
+  <xsl:param name="class"/>
+  <div id="{ id}-children">
+    <xsl:if test="@id != 'index'">
+      <xsl:attribute name="style">
+        <xsl:value-of select="'display: none'"/>
+      </xsl:attribute>
+    </xsl:if>
+    <xsl:if test="@id = 'index' or toc[.//doc]">
+      <div class="tocs">
+        <ul>
+          <xsl:for-each select="toc[../@id = 'index' or .//doc]">
+<!--             <xsl:sort select="number(../@id = 'index') * position()"/>
+            <xsl:sort select="normalize-space(title)"/>-->
+            <li class="toc">
+              <xsl:apply-templates mode="children.mode" select="."/>
+            </li>
+          </xsl:for-each>
+        </ul>
+      </div>
+    </xsl:if>
+    <xsl:if test="doc">
+      <div class="docs">
+        <dl>
+          <xsl:for-each select="doc">
+            <xsl:sort select="normalize-space(title)"/>
+            <dt class="doc">
+              <a href="{ href}" title="{ href}">
+                <xsl:if test="tooltip">
+                  <xsl:attribute name="title">
+                    <xsl:value-of select="tooltip"/>
+                  </xsl:attribute>
+                </xsl:if>
+                <xsl:value-of select="title"/>
+              </a>
+            </dt>
+            <dd>
+              <xsl:value-of select="description"/>
+            </dd>
+          </xsl:for-each>
+        </dl>
+      </div>
+    </xsl:if>
+  </div>
 </xsl:template>
 
 <xsl:template mode="body.mode" match="toc">
   <div class="body">
-    <h1>
-      <xsl:if test="icon">
-        <img src="{icon/@file}"/>
-      </xsl:if>
-      <xsl:apply-templates select="title[1]/node()"/>
-    </h1>
-    <div class="leftbar">
-    </div>
+    <xsl:call-template name="header">
+      <xsl:with-param name="class" select="'index'"/>
+    </xsl:call-template>
     <div class="rightbar">
-      <xsl:if test="toc[.//doc]">
-        <div class="tocs">
-          <ul>
-            <xsl:for-each select="toc[../@id = 'index' or .//doc]">
-              <xsl:sort select="number(../@id = 'index') * position()"/>
-              <xsl:sort select="normalize-space(title)"/>
-              <li class="toc">
-                <a href="x-yelp-toc:{ id}">
-                  <xsl:apply-templates select="title[1]/node()"/>
-                </a>
-              </li>
-            </xsl:for-each>
-          </ul>
-        </div>
-      </xsl:if>
-      <xsl:if test="doc">
-        <div class="docs">
-          <dl>
-            <xsl:for-each select="doc">
-              <xsl:sort select="normalize-space(title)"/>
-              <dt class="doc">
-                <a href="{ href}" title="{ href}">
-                  <xsl:if test="tooltip">
-                    <xsl:attribute name="title">
-                      <xsl:value-of select="tooltip"/>
-                    </xsl:attribute>
-                  </xsl:if>
-                  <xsl:value-of select="title"/>
-                </a>
-              </dt>
-              <dd>
-                <xsl:value-of select="description"/>
-              </dd>
-            </xsl:for-each>
-          </dl>
-        </div>
-      </xsl:if>
+      <xsl:call-template name="children">
+        <xsl:with-param name="class" select="'index'"/>
+      </xsl:call-template>
     </div>
   </div>
+</xsl:template>
+
+<xsl:template mode="children.mode" match="toc">
+  <xsl:call-template name="header">
+    <xsl:with-param name="class" select="'child'"/>
+  </xsl:call-template>
+  <xsl:call-template name="children">
+    <xsl:with-param name="class" select="'child'"/>
+  </xsl:call-template>
 </xsl:template>
 
 </xsl:stylesheet>


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