[yelp/yelp-3-0] [libyelp] Added Mallard documents to libyelp, more work to be done



commit 854d417cdee81e761df5c958a101e46de05ed72b
Author: Shaun McCance <shaunm gnome org>
Date:   Sat Oct 17 11:38:36 2009 -0500

    [libyelp] Added Mallard documents to libyelp, more work to be done

 libyelp/Makefile.am             |    3 +
 libyelp/yelp-document.c         |  487 +++++++++++++++++------------
 libyelp/yelp-document.h         |  148 +++++-----
 libyelp/yelp-mallard-document.c |  666 +++++++++++++++++++++++++++++++++++++++
 libyelp/yelp-mallard-document.h |   51 +++
 libyelp/yelp-settings.c         |   37 +++
 libyelp/yelp-settings.h         |   29 +-
 libyelp/yelp-transform.c        |   24 ++-
 libyelp/yelp-transform.h        |   16 +-
 libyelp/yelp-view.c             |   14 +-
 src/yelp-mallard.c              |  646 -------------------------------------
 src/yelp-mallard.h              |   53 ---
 tests/test-view.c               |    3 +-
 13 files changed, 1166 insertions(+), 1011 deletions(-)
---
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index 6599cfd..c22d748 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -4,6 +4,7 @@ libyelp_la_SOURCES =				\
 	yelp-debug.c				\
 	yelp-document.c				\
 	yelp-location-entry.c			\
+	yelp-mallard-document.c			\
 	yelp-settings.c				\
 	yelp-simple-document.c			\
 	yelp-transform.c			\
@@ -22,8 +23,10 @@ libyelp_la_LIBADD =				\
 libyelp_headers =				\
 	yelp-document.h				\
 	yelp-location-entry.h			\
+	yelp-mallard-document.h			\
 	yelp-settings.h				\
 	yelp-simple-document.h			\
+	yelp-transform.h			\
 	yelp-uri.h				\
 	yelp-view.h
 
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index 09bfb99..202ea7e 100644
--- a/libyelp/yelp-document.c
+++ b/libyelp/yelp-document.c
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Copyright (C) 2003-2009 Shaun McCance  <shaunm gnome org>
  *
@@ -27,7 +27,10 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#include "yelp-debug.h"
 #include "yelp-document.h"
+#include "yelp-mallard-document.h"
+#include "yelp-simple-document.h"
 
 typedef struct _Request Request;
 struct _Request {
@@ -36,29 +39,37 @@ struct _Request {
     GCancellable         *cancellable;
     YelpDocumentCallback  callback;
     gpointer              user_data;
+    GError               *error;
 
     gint                  idle_funcs;
 };
 
+typedef struct _Hash Hash;
+struct _Hash {
+    gpointer        null;
+    GHashTable     *hash;
+    GDestroyNotify  destroy;
+};
+
 struct _YelpDocumentPriv {
-    GMutex       *mutex;
+    GMutex *mutex;
 
-    GSList       *reqs_all;         /* Holds canonical refs, only free from here */
-    GHashTable   *reqs_by_page_id;  /* Indexed by page ID, contains GSList */
-    GSList       *reqs_pending;     /* List of requests that need a page */
+    GSList *reqs_all;         /* Holds canonical refs, only free from here */
+    Hash   *reqs_by_page_id;  /* Indexed by page ID, contains GSList */
+    GSList *reqs_pending;     /* List of requests that need a page */
 
     /* Real page IDs map to themselves, so this list doubles
      * as a list of all valid page IDs.
      */
-    GHashTable   *page_ids;      /* Mapping of fragment IDs to real page IDs */
-    GHashTable   *titles;        /* Mapping of page IDs to titles */
-    GHashTable   *mime_types;    /* Mapping of page IDs to mime types */
-    GHashTable   *contents;      /* Mapping of page IDs to string content */
+    Hash   *page_ids;      /* Mapping of fragment IDs to real page IDs */
+    Hash   *titles;        /* Mapping of page IDs to titles */
+    Hash   *mime_types;    /* Mapping of page IDs to mime types */
+    Hash   *contents;      /* Mapping of page IDs to string content */
 
-    GHashTable   *root_ids;      /* Mapping of page IDs to "previous page" IDs */
-    GHashTable   *prev_ids;      /* Mapping of page IDs to "previous page" IDs */
-    GHashTable   *next_ids;      /* Mapping of page IDs to "next page" IDs */
-    GHashTable   *up_ids;        /* Mapping of page IDs to "up page" IDs */
+    Hash   *root_ids;      /* Mapping of page IDs to "root page" IDs */
+    Hash   *prev_ids;      /* Mapping of page IDs to "previous page" IDs */
+    Hash   *next_ids;      /* Mapping of page IDs to "next page" IDs */
+    Hash   *up_ids;        /* Mapping of page IDs to "up page" IDs */
 
     GMutex       *str_mutex;
     GHashTable   *str_refs;
@@ -74,32 +85,43 @@ static void           yelp_document_dispose     (GObject              *object);
 static void           yelp_document_finalize    (GObject              *object);
 
 static gboolean       document_request_page     (YelpDocument         *document,
-						 const gchar          *page_id,
-						 GCancellable         *cancellable,
-						 YelpDocumentCallback  callback,
-						 gpointer              user_data);
+                                                 const gchar          *page_id,
+                                                 GCancellable         *cancellable,
+                                                 YelpDocumentCallback  callback,
+                                                 gpointer              user_data);
 static const gchar *  document_read_contents    (YelpDocument         *document,
-						 const gchar          *page_id);
+                                                 const gchar          *page_id);
 static void           document_finish_read      (YelpDocument         *document,
-						 const gchar          *contents);
+                                                 const gchar          *contents);
 static gchar *        document_get_mime_type    (YelpDocument         *document,
-						 const gchar          *mime_type);
+                                                 const gchar          *mime_type);
+
+static Hash *         hash_new                  (GDestroyNotify        destroy);
+static void           hash_free                 (Hash                 *hash);
+static gpointer       hash_lookup               (Hash                 *hash,
+                                                 const gchar          *key);
+static void           hash_replace              (Hash                 *hash,
+                                                 const gchar          *key,
+                                                 gpointer              value);
+static void           hash_remove               (Hash                 *hash,
+                                                 const gchar          *key);
+static void           hash_slist_insert         (Hash                 *hash,
+                                                 const gchar          *key,
+                                                 gpointer              value);
+static void           hash_slist_remove         (Hash                 *hash,
+                                                 const gchar          *key,
+                                                 gpointer              value);
 
 static void           request_cancel            (GCancellable         *cancellable,
-						 Request              *request);
+                                                 Request              *request);
 static gboolean       request_idle_contents     (Request              *request);
 static gboolean       request_idle_info         (Request              *request);
+static gboolean       request_idle_error        (Request              *request);
 static void           request_try_free          (Request              *request);
 static void           request_free              (Request              *request);
 
 static const gchar *  str_ref                   (const gchar          *str);
 static void           str_unref                 (const gchar          *str);
-static void           hash_slist_insert         (GHashTable           *hash,
-					         const gchar          *key,
-						 gpointer              value);
-static void           hash_slist_remove         (GHashTable           *hash,
-						 const gchar          *key,
-						 gpointer              value);
 
 #if 0
 static gboolean       request_idle_error        (Request             *request);
@@ -146,7 +168,7 @@ yelp_document_get_for_uri (YelpUri *uri)
 	/* FIXME */
 	break;
     case YELP_URI_DOCUMENT_TYPE_MALLARD:
-	/* FIXME */
+	document = yelp_mallard_document_new (uri);
 	break;
     case YELP_URI_DOCUMENT_TYPE_MAN:
 	/* FIXME */
@@ -202,24 +224,19 @@ yelp_document_init (YelpDocument *document)
 
     priv->mutex = g_mutex_new ();
 
-    priv->reqs_by_page_id =
-	g_hash_table_new_full (g_str_hash, g_str_equal,
-			       g_free,
-			       (GDestroyNotify) g_slist_free);
+    priv->reqs_by_page_id = hash_new ((GDestroyNotify) g_slist_free);
     priv->reqs_all = NULL;
     priv->reqs_pending = NULL;
 
-    priv->page_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->titles = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->mime_types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->contents = g_hash_table_new_full (g_str_hash, g_str_equal,
-					    g_free,
-					    (GDestroyNotify) str_unref);
-
-    priv->root_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->prev_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->next_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-    priv->up_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+    priv->page_ids = hash_new (g_free );
+    priv->titles = hash_new (g_free);
+    priv->mime_types = hash_new (g_free);
+    priv->contents = hash_new ((GDestroyNotify) str_unref);
+
+    priv->root_ids = hash_new (g_free);
+    priv->prev_ids = hash_new (g_free);
+    priv->next_ids = hash_new (g_free);
+    priv->up_ids = hash_new (g_free);
 }
 
 static void
@@ -228,7 +245,9 @@ yelp_document_dispose (GObject *object)
     YelpDocument *document = YELP_DOCUMENT (object);
 
     if (document->priv->reqs_all) {
-	g_slist_foreach (document->priv->reqs_all, request_try_free, NULL);
+	g_slist_foreach (document->priv->reqs_all,
+			 (GFunc) request_try_free,
+			 NULL);
 	g_slist_free (document->priv->reqs_all);
 	document->priv->reqs_all = NULL;
     }
@@ -242,18 +261,18 @@ yelp_document_finalize (GObject *object)
     YelpDocument *document = YELP_DOCUMENT (object);
 
     g_slist_free (document->priv->reqs_pending);
-    g_hash_table_destroy (document->priv->reqs_by_page_id);
+    hash_free (document->priv->reqs_by_page_id);
 
-    g_hash_table_destroy (document->priv->page_ids);
-    g_hash_table_destroy (document->priv->titles);
-    g_hash_table_destroy (document->priv->mime_types);
+    hash_free (document->priv->page_ids);
+    hash_free (document->priv->titles);
+    hash_free (document->priv->mime_types);
 
-    g_hash_table_destroy (document->priv->contents);
+    hash_free (document->priv->contents);
 
-    g_hash_table_destroy (document->priv->root_ids);
-    g_hash_table_destroy (document->priv->prev_ids);
-    g_hash_table_destroy (document->priv->next_ids);
-    g_hash_table_destroy (document->priv->up_ids);
+    hash_free (document->priv->root_ids);
+    hash_free (document->priv->prev_ids);
+    hash_free (document->priv->next_ids);
+    hash_free (document->priv->up_ids);
 
     g_mutex_free (document->priv->mutex);
 
@@ -271,7 +290,7 @@ yelp_document_get_page_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    ret = g_hash_table_lookup (document->priv->page_ids, id);
+    ret = hash_lookup (document->priv->page_ids, id);
     if (ret)
 	ret = g_strdup (ret);
 
@@ -289,11 +308,11 @@ yelp_document_set_page_id (YelpDocument *document,
 
     g_mutex_lock (document->priv->mutex);
 
-    g_hash_table_replace (document->priv->root_ids, g_strdup (id), g_strdup (page_id));
+    hash_replace (document->priv->page_ids, id, g_strdup (page_id));
 
-    if (!g_str_equal (id, page_id)) {
+    if (id != NULL && !g_str_equal (id, page_id)) {
 	GSList *reqs, *cur;
-	reqs = g_hash_table_lookup (document->priv->reqs_by_page_id, id);
+	reqs = hash_lookup (document->priv->reqs_by_page_id, id);
 	for (cur = reqs; cur != NULL; cur = cur->next) {
 	    Request *request = (Request *) cur->data;
 	    g_free (request->page_id);
@@ -301,7 +320,7 @@ yelp_document_set_page_id (YelpDocument *document,
 	    hash_slist_insert (document->priv->reqs_by_page_id, page_id, request);
 	}
 	if (reqs)
-	    g_hash_table_remove (document->priv->reqs_by_page_id, id);
+	    hash_remove (document->priv->reqs_by_page_id, id);
     }
 
     g_mutex_unlock (document->priv->mutex);
@@ -316,9 +335,9 @@ yelp_document_get_root_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->root_ids, real);
+	ret = hash_lookup (document->priv->root_ids, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -335,7 +354,7 @@ yelp_document_set_root_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    g_hash_table_replace (document->priv->root_ids, g_strdup (page_id), g_strdup (root_id));
+    hash_replace (document->priv->root_ids, page_id, g_strdup (root_id));
     g_mutex_unlock (document->priv->mutex);
 }
 
@@ -348,9 +367,9 @@ yelp_document_get_prev_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->prev_ids, real);
+	ret = hash_lookup (document->priv->prev_ids, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -367,7 +386,7 @@ yelp_document_set_prev_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    g_hash_table_replace (document->priv->prev_ids, g_strdup (page_id), g_strdup (prev_id));
+    hash_replace (document->priv->prev_ids, page_id, g_strdup (prev_id));
     g_mutex_unlock (document->priv->mutex);
 }
 
@@ -380,9 +399,9 @@ yelp_document_get_next_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->next_ids, real);
+	ret = hash_lookup (document->priv->next_ids, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -399,7 +418,7 @@ yelp_document_set_next_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    g_hash_table_replace (document->priv->next_ids, g_strdup (page_id), g_strdup (next_id));
+    hash_replace (document->priv->next_ids, page_id, g_strdup (next_id));
     g_mutex_unlock (document->priv->mutex);
 }
 
@@ -412,9 +431,9 @@ yelp_document_get_up_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->up_ids, real);
+	ret = hash_lookup (document->priv->up_ids, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -431,7 +450,7 @@ yelp_document_set_up_id (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    g_hash_table_replace (document->priv->up_ids, g_strdup (page_id), g_strdup (up_id));
+    hash_replace (document->priv->up_ids, page_id, g_strdup (up_id));
     g_mutex_unlock (document->priv->mutex);
 }
 
@@ -444,9 +463,9 @@ yelp_document_get_title (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->titles, real);
+	ret = hash_lookup (document->priv->titles, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -463,7 +482,7 @@ yelp_document_set_title (YelpDocument *document,
     g_assert (document != NULL && YELP_IS_DOCUMENT (document));
 
     g_mutex_lock (document->priv->mutex);
-    g_hash_table_replace (document->priv->titles, g_strdup (page_id), g_strdup (title));
+    hash_replace (document->priv->titles, page_id, g_strdup (title));
     g_mutex_unlock (document->priv->mutex);
 }
 
@@ -479,6 +498,8 @@ yelp_document_request_page (YelpDocument         *document,
     g_return_if_fail (YELP_IS_DOCUMENT (document));
     g_return_if_fail (YELP_DOCUMENT_GET_CLASS (document)->request_page != NULL);
 
+    debug_print (DB_FUNCTION, "entering\n");
+
     return YELP_DOCUMENT_GET_CLASS (document)->request_page (document,
 							     page_id,
 							     cancellable,
@@ -500,7 +521,7 @@ document_request_page (YelpDocument         *document,
     request = g_slice_new0 (Request);
     request->document = g_object_ref (document);
 
-    real_id = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real_id = hash_lookup (document->priv->page_ids, page_id);
     if (real_id)
 	request->page_id = g_strdup (real_id);
     else
@@ -523,12 +544,12 @@ document_request_page (YelpDocument         *document,
     document->priv->reqs_all = g_slist_prepend (document->priv->reqs_all, request);
     document->priv->reqs_pending = g_slist_prepend (document->priv->reqs_pending, request);
 
-    if (g_hash_table_lookup (document->priv->titles, request->page_id)) {
+    if (hash_lookup (document->priv->titles, request->page_id)) {
 	request->idle_funcs++;
 	g_idle_add ((GSourceFunc) request_idle_info, request);
     }
 
-    if (g_hash_table_lookup (document->priv->contents, request->page_id)) {
+    if (hash_lookup (document->priv->contents, request->page_id)) {
 	request->idle_funcs++;
 	g_idle_add ((GSourceFunc) request_idle_contents, request);
 	ret = TRUE;
@@ -559,8 +580,8 @@ document_read_contents (YelpDocument *document,
 
     g_mutex_lock (document->priv->mutex);
 
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
-    str = g_hash_table_lookup (document->priv->contents, real);
+    real = hash_lookup (document->priv->page_ids, page_id);
+    str = hash_lookup (document->priv->contents, real);
     if (str)
 	str_ref (str);
 
@@ -587,22 +608,25 @@ document_finish_read (YelpDocument *document,
 }
 
 void
-yelp_document_take_contents (YelpDocument *document,
+yelp_document_give_contents (YelpDocument *document,
 			     const gchar  *page_id,
 			     gchar        *contents,
 			     const gchar  *mime)
 {
     g_return_if_fail (YELP_IS_DOCUMENT (document));
 
+    debug_print (DB_FUNCTION, "entering\n");
+    debug_print (DB_ARG, "    page_id = \"%s\"\n", page_id);
+
     g_mutex_lock (document->priv->mutex);
 
-    g_hash_table_replace (document->priv->contents,
-			  g_strdup (page_id),
-			  (gpointer) str_ref (contents));
-   
-    g_hash_table_replace (document->priv->mime_types,
-			  g_strdup (page_id),
-			  g_strdup (mime));
+    hash_replace (document->priv->contents,
+                  page_id,
+                  (gpointer) str_ref (contents));
+
+    hash_replace (document->priv->mime_types,
+                  page_id,
+                  g_strdup (mime));
 
     g_mutex_unlock (document->priv->mutex);
 }
@@ -624,9 +648,9 @@ document_get_mime_type (YelpDocument *document,
     gchar *real, *ret = NULL;
 
     g_mutex_lock (document->priv->mutex);
-    real = g_hash_table_lookup (document->priv->page_ids, page_id);
+    real = hash_lookup (document->priv->page_ids, page_id);
     if (real) {
-	ret = g_hash_table_lookup (document->priv->mime_types, real);
+	ret = hash_lookup (document->priv->mime_types, real);
 	if (ret)
 	    ret = g_strdup (ret);
     }
@@ -649,7 +673,7 @@ yelp_document_signal (YelpDocument       *document,
 
     g_mutex_lock (document->priv->mutex);
 
-    reqs = g_hash_table_lookup (document->priv->reqs_by_page_id, page_id);
+    reqs = hash_lookup (document->priv->reqs_by_page_id, page_id);
     for (cur = reqs; cur != NULL; cur = cur->next) {
 	Request *request = (Request *) cur->data;
 	if (!request)
@@ -673,6 +697,126 @@ yelp_document_signal (YelpDocument       *document,
     g_mutex_unlock (document->priv->mutex);
 }
 
+void
+yelp_document_error_pending (YelpDocument *document,
+			     GError       *error)
+{
+    YelpDocumentPriv *priv = GET_PRIV (document);
+    GSList *cur;
+    Request *request;
+
+    g_assert (document != NULL && YELP_IS_DOCUMENT (document));
+
+    g_mutex_lock (priv->mutex);
+
+    if (priv->reqs_pending) {
+	for (cur = priv->reqs_pending; cur; cur = cur->next) {
+	    request = cur->data;
+	    request->error = g_error_copy (error);
+	    request->idle_funcs++;
+	    g_idle_add ((GSourceFunc) request_idle_error, request);
+	}
+
+	g_slist_free (priv->reqs_pending);
+	priv->reqs_pending = NULL;
+    }
+
+    g_mutex_unlock (priv->mutex);
+}
+
+/******************************************************************************/
+
+static Hash *
+hash_new (GDestroyNotify destroy)
+{
+    Hash *hash = g_new0 (Hash, 1);
+    hash->destroy = destroy;
+    hash->hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+					g_free, destroy);
+    return hash;
+}
+
+static void
+hash_free (Hash *hash)
+{
+    if (hash->null)
+	hash->destroy (hash->null);
+    g_hash_table_destroy (hash->hash);
+    g_free (hash);
+}
+
+static gpointer
+hash_lookup (Hash *hash, const gchar *key)
+{
+    if (key == NULL)
+	return hash->null;
+    else
+	return g_hash_table_lookup (hash->hash, key);
+}
+
+static void
+hash_replace (Hash        *hash,
+              const gchar *key,
+              gpointer     value)
+{
+    if (key == NULL) {
+        if (hash->null)
+            hash->destroy (hash->null);
+        hash->null = value;
+    }
+    else
+        g_hash_table_replace (hash->hash, g_strdup (key), value);
+}
+
+static void
+hash_remove (Hash        *hash,
+             const gchar *key)
+{
+    if (key == NULL) {
+        if (hash->null) {
+            hash->destroy (hash->null);
+            hash->null = NULL;
+        }
+    }
+    else
+        g_hash_table_remove (hash->hash, key);
+}
+
+static void
+hash_slist_insert (Hash        *hash,
+                   const gchar *key,
+                   gpointer     value)
+{
+    GSList *list;
+    list = hash_lookup (hash, key);
+    if (list) {
+        list->next = g_slist_prepend (list->next, value);
+    } else {
+        list = g_slist_prepend (NULL, value);
+        list = g_slist_prepend (list, NULL);
+        if (key == NULL)
+            hash->null = list;
+        else
+            g_hash_table_insert (hash->hash, g_strdup (key), list);
+    }
+}
+
+static void
+hash_slist_remove (Hash        *hash,
+                   const gchar *key,
+                   gpointer     value)
+{
+    GSList *list;
+    list = hash_lookup (hash, key);
+    if (list) {
+        list = g_slist_remove (list, value);
+        if (list->next == NULL)
+            hash_remove (hash, key);
+    }
+}
+
+/******************************************************************************/
+
 static void
 request_cancel (GCancellable *cancellable, Request *request)
 {
@@ -735,7 +879,7 @@ request_idle_info (Request *request)
 {
     YelpDocument *document;
     YelpDocumentCallback callback = NULL;
-    gpointer user_data = user_data;
+    gpointer user_data;
 
     g_assert (request != NULL && YELP_IS_DOCUMENT (request->document));
 
@@ -761,6 +905,48 @@ request_idle_info (Request *request)
     return FALSE;
 }
 
+static gboolean
+request_idle_error (Request *request)
+{
+    YelpDocument *document;
+    YelpDocumentPriv *priv;
+    YelpDocumentCallback callback = NULL;
+    GError *error = NULL;
+    gpointer user_data = user_data;
+
+    g_assert (request != NULL && YELP_IS_DOCUMENT (request->document));
+
+    if (g_cancellable_is_cancelled (request->cancellable)) {
+	request->idle_funcs--;
+	return FALSE;
+    }
+
+    document = g_object_ref (request->document);
+    priv = GET_PRIV (document);
+
+    g_mutex_lock (priv->mutex);
+
+    if (request->error) {
+	callback = request->callback;
+	user_data = request->user_data;
+	error = request->error;
+	request->error = NULL;
+	priv->reqs_pending = g_slist_remove (priv->reqs_pending, request);
+    }
+
+    request->idle_funcs--;
+    g_mutex_unlock (priv->mutex);
+
+    if (callback)
+	callback (document,
+		  YELP_DOCUMENT_SIGNAL_ERROR,
+		  user_data,
+		  error);
+
+    g_object_unref (document);
+    return FALSE;
+}
+
 static void
 request_try_free (Request *request)
 {
@@ -780,6 +966,9 @@ request_free (Request *request)
     g_free (request->page_id);
     g_object_unref (request->cancellable);
 
+    if (request->error)
+	g_error_free (request->error);
+
     g_slice_free (Request, request);
 }
 
@@ -829,37 +1018,6 @@ str_unref (const gchar *str)
 
     g_static_mutex_unlock (&str_mutex);
 }
-
-static void
-hash_slist_insert (GHashTable  *hash,
-		   const gchar *key,
-		   gpointer     value)
-{
-    GSList *list;
-    list = g_hash_table_lookup (hash, key);
-    if (list) {
-	list->next = g_slist_prepend (list->next, value);
-    } else {
-	list = g_slist_prepend (NULL, value);
-	list = g_slist_prepend (list, NULL);
-	g_hash_table_insert (hash, g_strdup (key), list);
-    }
-}
-
-static void
-hash_slist_remove (GHashTable  *hash,
-		   const gchar *key,
-		   gpointer     value)
-{
-    GSList *list;
-    list = g_hash_table_lookup (hash, key);
-    if (list) {
-	list = g_slist_remove (list, value);
-	if (list->next == NULL)
-	    g_hash_table_remove (hash, key);
-    }
-}
-
 #if 0
 
 void
@@ -877,9 +1035,9 @@ yelp_document_add_page (YelpDocument *document, gchar *page_id, const gchar *con
 
     g_mutex_lock (priv->mutex);
 
-    g_hash_table_replace (priv->contents,
-			  g_strdup (page_id),
-			  str_ref ((gchar *) contents));
+    hashh_replace (priv->contents,
+                   g_strdup (page_id),
+                   str_ref ((gchar *) contents));
 
     reqs = g_hash_table_lookup (priv->reqs_by_page_id, page_id);
     for (cur = reqs; cur != NULL; cur = cur->next) {
@@ -958,40 +1116,6 @@ yelp_document_error_page (YelpDocument *document, gchar *page_id, YelpError *err
 }
 
 void
-yelp_document_error_pending (YelpDocument *document, YelpError *error)
-{
-    GSList *cur;
-    Request *request;
-    YelpDocumentPriv *priv;
-
-    g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
-    debug_print (DB_FUNCTION, "entering\n");
-    priv = document->priv;
-
-    g_mutex_lock (priv->mutex);
-
-    if (priv->reqs_pending) {
-	for (cur = priv->reqs_pending; cur; cur = cur->next) {
-	    request = cur->data;
-	    if (cur->next)
-		request->error = yelp_error_copy (error);
-	    else
-		request->error = error;
-	    request->idle_funcs++;
-	    g_idle_add ((GSourceFunc) request_idle_error, request);
-	}
-
-	g_slist_free (priv->reqs_pending);
-	priv->reqs_pending = NULL;
-    } else {
-	yelp_error_free (error);
-    }
-
-    g_mutex_unlock (priv->mutex);
-}
-
-void
 yelp_document_final_pending (YelpDocument *document, YelpError *error)
 {
     YelpDocumentPriv *priv;
@@ -1015,53 +1139,6 @@ yelp_document_final_pending (YelpDocument *document, YelpError *error)
 
 /******************************************************************************/
 
-static gboolean
-request_idle_error (Request *request)
-{
-    YelpDocument *document;
-    YelpDocumentPriv *priv;
-    YelpDocumentFunc  func = NULL;
-    YelpError *error = NULL;
-    gint req_id = 0;
-    gpointer user_data = user_data;
-
-    g_assert (request != NULL && YELP_IS_DOCUMENT (request->document));
-
-    if (request->cancel) {
-	request->idle_funcs--;
-	return FALSE;
-    }
-
-    debug_print (DB_FUNCTION, "entering\n");
-
-    document = g_object_ref (request->document);
-    priv = document->priv;
-
-    g_mutex_lock (priv->mutex);
-
-    if (request->error) {
-	func = request->func;
-	req_id = request->req_id;
-	user_data = request->user_data;
-	error = request->error;
-	request->error = NULL;
-
-	priv->reqs_pending = g_slist_remove (priv->reqs_pending, request);
-    }
-
-    request->idle_funcs--;
-    g_mutex_unlock (priv->mutex);
-
-    if (func)
-	func (document,
-	      YELP_DOCUMENT_SIGNAL_ERROR,
-	      req_id,
-	      error,
-	      user_data);
-
-    g_object_unref (document);
-    return FALSE;
-}
 
 
 static gboolean
diff --git a/libyelp/yelp-document.h b/libyelp/yelp-document.h
index 6ffecff..60e4c53 100644
--- a/libyelp/yelp-document.h
+++ b/libyelp/yelp-document.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Copyright (C) 2003-2009 Shaun McCance  <shaunm gnome org>
  *
@@ -48,9 +48,9 @@ typedef enum {
 } YelpDocumentSignal;
 
 typedef void      (*YelpDocumentCallback)      (YelpDocument         *document,
-						YelpDocumentSignal    signal,
-						gpointer              user_data,
-						GError               *error);
+                                                YelpDocumentSignal    signal,
+                                                gpointer              user_data,
+                                                GError               *error);
 
 struct _YelpDocument {
     GObject           parent;
@@ -62,16 +62,16 @@ struct _YelpDocumentClass {
 
     /* Virtual Functions */
     gboolean      (*request_page)              (YelpDocument         *document,
-						const gchar          *page_id,
-						GCancellable         *cancellable,
-						YelpDocumentCallback  callback,
-						gpointer              user_data);
+                                                const gchar          *page_id,
+                                                GCancellable         *cancellable,
+                                                YelpDocumentCallback  callback,
+                                                gpointer              user_data);
     const gchar * (*read_contents)             (YelpDocument         *document,
-						const gchar          *page_id);
+                                                const gchar          *page_id);
     void          (*finish_read)               (YelpDocument         *document,
-						const gchar          *contents);
+                                                const gchar          *contents);
     gchar *       (*get_mime_type)             (YelpDocument         *document,
-						const gchar          *mime_type);
+                                                const gchar          *mime_type);
 
 };
 
@@ -80,77 +80,79 @@ GType             yelp_document_get_type       (void);
 YelpDocument *    yelp_document_get_for_uri    (YelpUri              *uri);
 
 gboolean          yelp_document_request_page   (YelpDocument         *document,
-					        const gchar          *page_id,
-					        GCancellable         *cancellable,
-						YelpDocumentCallback  callback,
-					        gpointer              user_data);
-
-void              yelp_document_take_contents  (YelpDocument         *document,
-						const gchar          *page_id,
-						gchar                *contents,
-						const gchar          *mime);
+                                                const gchar          *page_id,
+                                                GCancellable         *cancellable,
+                                                YelpDocumentCallback  callback,
+                                                gpointer              user_data);
+
+void              yelp_document_give_contents  (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                gchar                *contents,
+                                                const gchar          *mime);
 gchar *           yelp_document_get_mime_type  (YelpDocument         *document,
-						const gchar          *page_id);
+                                                const gchar          *page_id);
 const gchar *     yelp_document_read_contents  (YelpDocument         *document,
-						const gchar          *page_id);
+                                                const gchar          *page_id);
 void              yelp_document_finish_read    (YelpDocument         *document,
-						const gchar          *contents);
-
-gchar *           yelp_document_get_page_id    (YelpDocument        *document,
-						const gchar         *id);
-void              yelp_document_set_page_id    (YelpDocument        *document,
-						const gchar         *id,
-						const gchar         *page_id);
-
-gchar *           yelp_document_get_root_id    (YelpDocument        *document,
-						const gchar         *page_id);
-void              yelp_document_set_root_id    (YelpDocument        *document,
-						const gchar         *page_id,
-						const gchar         *root_id);
-
-gchar *           yelp_document_get_prev_id    (YelpDocument        *document,
-						const gchar         *page_id);
-void              yelp_document_set_prev_id    (YelpDocument        *document,
-						const gchar         *page_id,
-						const gchar         *prev_id);
-
-char *            yelp_document_get_next_id    (YelpDocument        *document,
-						const gchar         *page_id);
-void              yelp_document_set_next_id    (YelpDocument        *document,
-						const gchar         *page_id,
-						const gchar         *next_id);
-
-gchar *           yelp_document_get_up_id      (YelpDocument        *document,
-						const gchar         *page_id);
-void              yelp_document_set_up_id      (YelpDocument        *document,
-						const gchar         *page_id,
-						const gchar         *up_id);
-
-gchar *           yelp_document_get_title      (YelpDocument        *document,
-						const gchar         *page_id);
-void              yelp_document_set_title      (YelpDocument        *document,
-						const gchar         *page_id,
-						const gchar         *title);
-
-gboolean          yelp_document_has_page       (YelpDocument        *document,
-						const gchar         *page_id);
-
-void              yelp_document_signal         (YelpDocument        *document,
-						const gchar         *page_id,
-						YelpDocumentSignal   signal,
-						GError              *error);
+                                                const gchar          *contents);
+
+gchar *           yelp_document_get_page_id    (YelpDocument         *document,
+                                                const gchar          *id);
+void              yelp_document_set_page_id    (YelpDocument         *document,
+                                                const gchar          *id,
+                                                const gchar          *page_id);
+
+gchar *           yelp_document_get_root_id    (YelpDocument         *document,
+                                                const gchar          *page_id);
+void              yelp_document_set_root_id    (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                const gchar          *root_id);
+
+gchar *           yelp_document_get_prev_id    (YelpDocument         *document,
+                                                const gchar          *page_id);
+void              yelp_document_set_prev_id    (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                const gchar          *prev_id);
+
+char *            yelp_document_get_next_id    (YelpDocument         *document,
+                                                const gchar          *page_id);
+void              yelp_document_set_next_id    (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                const gchar          *next_id);
+
+gchar *           yelp_document_get_up_id      (YelpDocument         *document,
+                                                const gchar          *page_id);
+void              yelp_document_set_up_id      (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                const gchar          *up_id);
+
+gchar *           yelp_document_get_title      (YelpDocument         *document,
+                                                const gchar          *page_id);
+void              yelp_document_set_title      (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                const gchar          *title);
+
+gboolean          yelp_document_has_page       (YelpDocument         *document,
+                                                const gchar          *page_id);
+
+void              yelp_document_signal         (YelpDocument         *document,
+                                                const gchar          *page_id,
+                                                YelpDocumentSignal    signal,
+                                                GError               *error);
+void              yelp_document_error_pending  (YelpDocument         *document,
+                                                GError               *error);
 /* FIXME */
 /*
 void              yelp_document_error_request  (YelpDocument        *document,
-						gint                 req_id,
-						YelpError           *error);
+                                                gint                 req_id,
+                                                YelpError           *error);
 void              yelp_document_error_page     (YelpDocument        *document,
-						gchar               *page_id,
-						YelpError           *error);
+                                                gchar               *page_id,
+                                                YelpError           *error);
 void              yelp_document_error_pending  (YelpDocument        *document,
-						YelpError           *error);
+                                                YelpError           *error);
 void              yelp_document_final_pending  (YelpDocument        *document,
-						YelpError           *error);
+                                                YelpError           *error);
 */
 
 G_END_DECLS
diff --git a/libyelp/yelp-mallard-document.c b/libyelp/yelp-mallard-document.c
new file mode 100644
index 0000000..75d7f78
--- /dev/null
+++ b/libyelp/yelp-mallard-document.c
@@ -0,0 +1,666 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2009 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 <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xinclude.h>
+
+#include "yelp-error.h"
+#include "yelp-mallard-document.h"
+#include "yelp-settings.h"
+#include "yelp-transform.h"
+#include "yelp-debug.h"
+
+#define STYLESHEET DATADIR"/yelp/xslt/mal2html.xsl"
+#define MALLARD_NS "http://projectmallard.org/1.0/";
+
+typedef enum {
+    MALLARD_STATE_BLANK,
+    MALLARD_STATE_THINKING,
+    MALLARD_STATE_IDLE,
+    MALLARD_STATE_STOP
+} MallardState;
+
+typedef struct {
+    YelpMallardDocument *mallard;
+
+    gchar         *page_id;
+    gchar         *filename;
+    xmlDocPtr      xmldoc;
+    YelpTransform *transform;
+
+    guint          chunk_ready;
+    guint          finished;
+    guint          error;
+
+    xmlNodePtr     cur;
+    xmlNodePtr     cache;
+    gboolean       link_title;
+    gboolean       sort_title;
+} MallardPageData;
+
+static void           yelp_mallard_document_class_init (YelpMallardDocumentClass *klass);
+static void           yelp_mallard_document_init       (YelpMallardDocument      *mallard);
+static void           yelp_mallard_document_dispose    (GObject                  *object);
+static void           yelp_mallard_document_finalize   (GObject                  *object);
+
+static gboolean       mallard_request_page      (YelpDocument         *document,
+                                                 const gchar          *page_id,
+                                                 GCancellable         *cancellable,
+                                                 YelpDocumentCallback  callback,
+                                                 gpointer              user_data);
+
+static void           transform_chunk_ready     (YelpTransform        *transform,
+                                                 gchar                *chunk_id,
+                                                 MallardPageData      *page_data);
+static void           transform_finished        (YelpTransform        *transform,
+                                                 MallardPageData      *page_data);
+static void           transform_error           (YelpTransform        *transform,
+                                                 MallardPageData      *page_data);
+
+static void           mallard_think             (YelpMallardDocument  *mallard);
+static void           mallard_try_run           (YelpMallardDocument  *mallard,
+                                                 const gchar          *page_id);
+
+static void           mallard_page_data_cancel  (MallardPageData      *page_data);
+static void           mallard_page_data_walk    (MallardPageData      *page_data);
+static void           mallard_page_data_info    (MallardPageData      *page_data,
+                                                 xmlNodePtr            info_node,
+                                                 xmlNodePtr            cache_node);
+static void           mallard_page_data_run     (MallardPageData      *page_data);
+static void           mallard_page_data_free    (MallardPageData      *page_data);
+
+
+G_DEFINE_TYPE (YelpMallardDocument, yelp_mallard_document, YELP_TYPE_DOCUMENT);
+#define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_MALLARD_DOCUMENT, YelpMallardDocumentPrivate))
+
+typedef struct _YelpMallardDocumentPrivate  YelpMallardDocumentPrivate;
+struct _YelpMallardDocumentPrivate {
+    YelpUri       *uri;
+    MallardState   state;
+
+    GMutex        *mutex;
+    GThread       *thread;
+    gboolean       thread_running;
+    GSList        *pending;
+
+    xmlDocPtr      cache;
+    xmlNsPtr       cache_ns;
+    GHashTable    *pages_hash;
+};
+
+/******************************************************************************/
+
+static void
+yelp_mallard_document_class_init (YelpMallardDocumentClass *klass)
+{
+    GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
+    YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
+
+    object_class->dispose = yelp_mallard_document_dispose;
+    object_class->finalize = yelp_mallard_document_finalize;
+
+    document_class->request_page = mallard_request_page;
+
+    g_type_class_add_private (klass, sizeof (YelpMallardDocumentPrivate));
+}
+
+static void
+yelp_mallard_document_init (YelpMallardDocument *mallard)
+{
+    YelpMallardDocumentPrivate *priv = GET_PRIV (mallard);
+    xmlNodePtr cur;
+
+    priv->mutex = g_mutex_new ();
+
+    priv->thread_running = FALSE;
+
+    priv->cache = xmlNewDoc (BAD_CAST "1.0");
+    priv->cache_ns = xmlNewNs (NULL, BAD_CAST MALLARD_NS, BAD_CAST "mal");
+    cur = xmlNewDocNode (priv->cache, priv->cache_ns, BAD_CAST "cache", NULL);
+    xmlDocSetRootElement (priv->cache, cur);
+    priv->cache_ns->next = cur->nsDef;
+    cur->nsDef = priv->cache_ns;
+    priv->pages_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                              NULL,
+                                              (GDestroyNotify) mallard_page_data_free);
+}
+
+static void
+yelp_mallard_document_dispose (GObject *object)
+{
+    G_OBJECT_CLASS (yelp_mallard_document_parent_class)->dispose (object);
+}
+
+static void
+yelp_mallard_document_finalize (GObject *object)
+{
+    YelpMallardDocumentPrivate *priv = GET_PRIV (object);
+
+    g_object_unref (priv->uri);
+    g_mutex_free (priv->mutex);
+    g_hash_table_destroy (priv->pages_hash);
+
+    G_OBJECT_CLASS (yelp_mallard_document_parent_class)->finalize (object);
+}
+
+/******************************************************************************/
+
+YelpDocument *
+yelp_mallard_document_new (YelpUri *uri)
+{
+    YelpMallardDocument *mallard;
+    YelpMallardDocumentPrivate *priv;
+
+    g_return_val_if_fail (uri != NULL, NULL);
+
+    mallard = (YelpMallardDocument *) g_object_new (YELP_TYPE_MALLARD_DOCUMENT, NULL);
+    priv = GET_PRIV (mallard);
+    priv->uri = g_object_ref (uri);
+
+    yelp_document_set_page_id ((YelpDocument *) mallard, NULL, "index");
+    yelp_document_set_page_id ((YelpDocument *) mallard, "index", "index");
+
+    return (YelpDocument *) mallard;
+}
+
+
+static gboolean
+mallard_request_page (YelpDocument         *document,
+                      const gchar          *page_id,
+                      GCancellable         *cancellable,
+                      YelpDocumentCallback  callback,
+                      gpointer              user_data)
+{
+    YelpMallardDocumentPrivate *priv = GET_PRIV (document);
+    gchar *docuri;
+    GError *error;
+    gboolean handled;
+
+    debug_print (DB_FUNCTION, "entering\n");
+
+    if (page_id == NULL)
+        page_id = "index";
+
+    handled =
+        YELP_DOCUMENT_CLASS (yelp_mallard_document_parent_class)->request_page (document,
+                                                                                page_id,
+                                                                                cancellable,
+                                                                                callback,
+                                                                                user_data);
+    if (handled) {
+        return TRUE;
+    }
+
+    g_mutex_lock (priv->mutex);
+
+    if (priv->state == MALLARD_STATE_BLANK) {
+        priv->state = MALLARD_STATE_THINKING;
+        priv->thread_running = TRUE;
+        g_object_ref (document);
+        priv->thread = g_thread_create ((GThreadFunc) mallard_think,
+                                        document, FALSE, NULL);
+    }
+
+    switch (priv->state) {
+    case MALLARD_STATE_THINKING:
+        priv->pending = g_slist_prepend (priv->pending, (gpointer) g_strdup (page_id));
+        break;
+    case MALLARD_STATE_IDLE:
+        mallard_try_run ((YelpMallardDocument *) document, page_id);
+        break;
+    case MALLARD_STATE_BLANK:
+    case MALLARD_STATE_STOP:
+        docuri = yelp_uri_get_document_uri (priv->uri);
+        error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
+                             _("The page â??%sâ?? was not found in the document â??%sâ??."),
+                             page_id, docuri);
+        g_free (docuri);
+        yelp_document_signal (document, page_id,
+                              YELP_DOCUMENT_SIGNAL_ERROR,
+                              error);
+        g_error_free (error);
+	break;
+    }
+
+    g_mutex_unlock (priv->mutex);
+
+    return FALSE;
+}
+
+/******************************************************************************/
+
+static void
+mallard_think (YelpMallardDocument *mallard)
+{
+    YelpMallardDocumentPrivate *priv = GET_PRIV (mallard);
+    GError *error = NULL;
+    YelpDocument *document;
+    gchar **search_path;
+
+    GFile *gfile;
+    GFileEnumerator *children;
+    GFileInfo *pageinfo;
+
+    search_path = yelp_uri_get_search_path (priv->uri);
+
+    if (!search_path || search_path[0] == NULL ||
+        !g_file_test (search_path[0], G_FILE_TEST_IS_DIR)) {
+        /* This basically only happens when someone passes an actual directory
+           manually, which will have a singleton search path.
+         */
+        error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                             _("The directory â??%sâ?? does not exist."),
+                             search_path[0]);
+	yelp_document_error_pending ((YelpDocument *) document, error);
+	goto done;
+    }
+
+    gfile = yelp_uri_get_file (priv->uri);
+    children = g_file_enumerate_children (gfile,
+                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
+                                          G_FILE_QUERY_INFO_NONE,
+                                          NULL, NULL);
+    while ((pageinfo = g_file_enumerator_next_file (children, NULL, NULL))) {
+        MallardPageData *page_data;
+        gchar *filename;
+        GFile *pagefile;
+        filename = g_file_info_get_attribute_as_string (pageinfo,
+                                                        G_FILE_ATTRIBUTE_STANDARD_NAME);
+        if (!g_str_has_suffix (filename, ".page")) {
+            g_free (filename);
+            g_object_unref (pageinfo);
+            continue;
+        }
+        page_data = g_new0 (MallardPageData, 1);
+        page_data->mallard = mallard;
+        pagefile = g_file_resolve_relative_path (gfile, filename);
+        page_data->filename = g_file_get_path (pagefile);
+        mallard_page_data_walk (page_data);
+        if (page_data->page_id == NULL) {
+            mallard_page_data_free (page_data);
+        } else {
+            g_mutex_lock (priv->mutex);
+            g_hash_table_insert (priv->pages_hash, page_data->page_id, page_data);
+            g_mutex_unlock (priv->mutex);
+        }
+        g_object_unref (pagefile);
+        g_free (filename);
+        g_object_unref (pageinfo);
+    }
+
+    g_mutex_lock (priv->mutex);
+    priv->state = MALLARD_STATE_IDLE;
+    while (priv->pending) {
+        gchar *page_id;
+        page_id = (gchar *) priv->pending->data;
+        mallard_try_run (mallard, page_id);
+        g_free (page_id);
+        priv->pending = g_slist_delete_link (priv->pending, priv->pending);
+    }
+    g_mutex_unlock (priv->mutex);
+
+ done:
+    g_object_unref (children);
+    g_object_unref (gfile);
+
+    priv->thread_running = FALSE;
+    g_object_unref (mallard);
+}
+
+static void
+mallard_try_run (YelpMallardDocument *mallard,
+                 const gchar         *page_id)
+{
+    /* We expect to be in a locked mutex when this function is called. */
+    YelpMallardDocumentPrivate *priv = GET_PRIV (mallard);
+    MallardPageData *page_data;
+    GError *error;
+
+    page_data = g_hash_table_lookup (priv->pages_hash, page_id);
+    if (page_data == NULL) {
+        gchar *docuri = yelp_uri_get_document_uri (priv->uri);
+        error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                             _("The page â??%sâ?? was not found in the document â??%sâ??."),
+                             page_id, docuri);
+        g_free (docuri);
+        yelp_document_signal ((YelpDocument *) mallard, page_id,
+                              YELP_DOCUMENT_SIGNAL_ERROR,
+                              error);
+        return;
+    }
+
+    mallard_page_data_run (page_data);
+}
+
+/******************************************************************************/
+/** MallardPageData ***********************************************************/
+
+static void
+mallard_page_data_cancel (MallardPageData *page_data)
+{
+    if (page_data->transform) {
+        if (page_data->chunk_ready) {
+            g_signal_handler_disconnect (page_data->transform, page_data->chunk_ready);
+            page_data->chunk_ready = 0;
+        }
+        if (page_data->finished) {
+            g_signal_handler_disconnect (page_data->transform, page_data->finished);
+            page_data->finished = 0;
+        }
+        if (page_data->error) {
+            g_signal_handler_disconnect (page_data->transform, page_data->error);
+            page_data->error = 0;
+        }
+        yelp_transform_cancel (page_data->transform);
+        g_object_unref (page_data->transform);
+        page_data->transform = NULL;
+    }
+}
+
+static void
+mallard_page_data_walk (MallardPageData *page_data)
+{
+    YelpMallardDocumentPrivate *priv = GET_PRIV (page_data->mallard);
+    xmlParserCtxtPtr parserCtxt = NULL;
+    xmlChar *id = NULL;
+
+    if (page_data->cur == NULL) {
+        parserCtxt = xmlNewParserCtxt ();
+        page_data->xmldoc = xmlCtxtReadFile (parserCtxt,
+                                             (const char *) page_data->filename, NULL,
+                                             XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
+                                             XML_PARSE_NOENT   | XML_PARSE_NONET   );
+        if (page_data->xmldoc == NULL)
+            goto done;
+        page_data->cur = xmlDocGetRootElement (page_data->xmldoc);
+        page_data->cache = xmlDocGetRootElement (priv->cache);
+        mallard_page_data_walk (page_data);
+    } else {
+        xmlNodePtr child, oldcur, oldcache, info;
+
+        id = xmlGetProp (page_data->cur, BAD_CAST "id");
+        if (id == NULL)
+            goto done;
+
+        page_data->cache = xmlNewChild (page_data->cache,
+                                        priv->cache_ns,
+                                        page_data->cur->name,
+                                        NULL);
+
+        if (xmlStrEqual (page_data->cur->name, BAD_CAST "page")) {
+            page_data->page_id = g_strdup ((gchar *) id);
+            xmlSetProp (page_data->cache, BAD_CAST "id", id);
+        } else {
+            gchar *newid = g_strdup_printf ("%s#%s", page_data->page_id, id);
+            xmlSetProp (page_data->cache, BAD_CAST "id", BAD_CAST newid);
+            g_free (newid);
+        }
+
+        info = xmlNewChild (page_data->cache,
+                            priv->cache_ns,
+                            BAD_CAST "info", NULL);
+        page_data->link_title = FALSE;
+        page_data->sort_title = FALSE;
+        for (child = page_data->cur->children; child; child = child->next) {
+            if (child->type != XML_ELEMENT_NODE)
+                continue;
+            if (xmlStrEqual (child->name, BAD_CAST "info")) {
+                mallard_page_data_info (page_data, child, info);
+            }
+            else if (xmlStrEqual (child->name, BAD_CAST "title")) {
+                xmlNodePtr node;
+                xmlNodePtr title_node = xmlNewChild (page_data->cache,
+                                                     priv->cache_ns,
+                                                     BAD_CAST "title", NULL);
+                for (node = child->children; node; node = node->next) {
+                    xmlAddChild (title_node, xmlCopyNode (node, 1));
+                }
+                if (!page_data->link_title) {
+                    xmlNodePtr title_node = xmlNewChild (info,
+                                                         priv->cache_ns,
+                                                         BAD_CAST "title", NULL);
+                    xmlSetProp (title_node, BAD_CAST "type", BAD_CAST "link");
+                    for (node = child->children; node; node = node->next) {
+                        xmlAddChild (title_node, xmlCopyNode (node, 1));
+                    }
+                }
+                if (!page_data->sort_title) {
+                    xmlNodePtr title_node = xmlNewChild (info,
+                                                         priv->cache_ns,
+                                                         BAD_CAST "title", NULL);
+                    xmlSetProp (title_node, BAD_CAST "type", BAD_CAST "sort");
+                    for (node = child->children; node; node = node->next) {
+                        xmlAddChild (title_node, xmlCopyNode (node, 1));
+                    }
+                }
+            }
+            else if (xmlStrEqual (child->name, BAD_CAST "section")) {
+                oldcur = page_data->cur;
+                oldcache = page_data->cache;
+                page_data->cur = child;
+                mallard_page_data_walk (page_data);
+                page_data->cur = oldcur;
+                page_data->cache = oldcache;
+            }
+        }
+    }
+
+ done:
+    if (id)
+        xmlFree (id);
+    if (parserCtxt)
+	xmlFreeParserCtxt (parserCtxt);
+}
+
+static void
+mallard_page_data_info (MallardPageData *page_data,
+                        xmlNodePtr       info_node,
+                        xmlNodePtr       cache_node)
+{
+    xmlNodePtr child;
+
+    for (child = info_node->children; child; child = child->next) {
+        if (xmlStrEqual (child->name, BAD_CAST "info")) {
+            mallard_page_data_info (page_data, child, cache_node);
+        }
+        else if (xmlStrEqual (child->name, BAD_CAST "title")) {
+            xmlNodePtr node, title_node;
+            xmlChar *type, *role;
+            title_node = xmlCopyNode (child, 1);
+            xmlAddChild (cache_node, title_node);
+
+            type = xmlGetProp (child, BAD_CAST "type");
+            role = xmlGetProp (child, BAD_CAST "role");
+
+            if (xmlStrEqual (type, BAD_CAST "link") && role == NULL)
+                page_data->link_title = TRUE;
+            if (xmlStrEqual (type, BAD_CAST "sort"))
+                page_data->sort_title = TRUE;
+        }
+        else if (xmlStrEqual (child->name, BAD_CAST "desc") ||
+                 xmlStrEqual (child->name, BAD_CAST "link")) {
+            xmlAddChild (cache_node, xmlCopyNode (child, 1));
+        }
+    }
+}
+
+static void
+mallard_page_data_run (MallardPageData *page_data)
+{
+    YelpSettings *settings = yelp_settings_get_default ();
+    YelpMallardDocumentPrivate *priv = GET_PRIV (page_data->mallard);
+    gint i, ix;
+    gchar **params = NULL;
+    page_data->transform = yelp_transform_new ();
+    /* FIXME: handle error */
+    yelp_transform_set_stylesheet (page_data->transform, STYLESHEET, NULL);
+
+    page_data->chunk_ready =
+        g_signal_connect (page_data->transform, "chunk-ready",
+                          (GCallback) transform_chunk_ready,
+                          page_data);
+    page_data->finished =
+        g_signal_connect (page_data->transform, "finished",
+                          (GCallback) transform_finished,
+                          page_data);
+    page_data->error =
+        g_signal_connect (page_data->transform, "error",
+                          (GCallback) transform_error,
+                          page_data);
+
+    params = g_new0 (gchar *,
+                     (2*YELP_SETTINGS_NUM_COLORS) + (2*YELP_SETTINGS_NUM_ICONS) + 3);
+    for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++) {
+        gchar *val;
+        ix = 2 * i;
+        params[ix] = g_strdup (yelp_settings_get_color_param (i));
+        val = yelp_settings_get_color (settings, i);
+        params[ix + 1] = g_strdup_printf ("\"%s\"", val);
+        g_free (val);
+    }
+    for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
+        gchar *val;
+        ix = 2 * (YELP_SETTINGS_NUM_COLORS + i);
+        params[ix] = g_strdup (yelp_settings_get_icon_param (i));
+        val = yelp_settings_get_icon (settings, i);
+        params[ix + 1] = g_strdup_printf ("\"%s\"", val);
+        g_free (val);
+    }
+    ix = 2 * (YELP_SETTINGS_NUM_COLORS + YELP_SETTINGS_NUM_ICONS);
+    params[ix++] = g_strdup ("theme.icon.admon.size");
+    params[ix++] = g_strdup_printf ("%i", yelp_settings_get_icon_size (settings));
+    params[ix] = NULL;
+
+    yelp_transform_set_aux (page_data->transform,
+                            priv->cache);
+
+    /* FIXME: handle error */
+    yelp_transform_start (page_data->transform,
+			  page_data->xmldoc,
+			  (const gchar * const *) params,
+                          NULL);
+    g_strfreev (params);
+}
+
+static void
+mallard_page_data_free (MallardPageData *page_data)
+{
+    mallard_page_data_cancel (page_data);
+    g_free (page_data->page_id);
+    g_free (page_data->filename);
+    if (page_data->xmldoc)
+        xmlFreeDoc (page_data->xmldoc);
+    g_free (page_data);
+}
+
+/******************************************************************************/
+/** YelpTransform *************************************************************/
+
+static void
+transform_chunk_ready (YelpTransform   *transform,
+                       gchar           *chunk_id,
+                       MallardPageData *page_data)
+{
+    YelpMallardDocumentPrivate *priv;
+    gchar *content;
+
+    debug_print (DB_FUNCTION, "entering\n");
+
+    g_assert (page_data != NULL && page_data->mallard != NULL &&
+              YELP_IS_MALLARD_DOCUMENT (page_data->mallard));
+    g_assert (transform == page_data->transform);
+
+    priv = GET_PRIV (page_data->mallard);
+
+    if (priv->state == MALLARD_STATE_STOP) {
+        mallard_page_data_cancel (page_data);
+        return;
+    }
+
+    content = yelp_transform_take_chunk (transform, chunk_id);
+    yelp_document_give_contents (YELP_DOCUMENT (page_data->mallard),
+                                 chunk_id,
+                                 content,
+                                 "application/xhtml+xml");
+
+    yelp_document_signal (YELP_DOCUMENT (page_data->mallard),
+                          chunk_id,
+                          YELP_DOCUMENT_SIGNAL_CONTENTS,
+                          NULL);
+}
+
+static void
+transform_finished (YelpTransform   *transform,
+                    MallardPageData *page_data)
+{
+    YelpMallardDocumentPrivate *priv;
+
+    g_assert (page_data != NULL && page_data->mallard != NULL &&
+              YELP_IS_MALLARD_DOCUMENT (page_data->mallard));
+    g_assert (transform == page_data->transform);
+
+    priv = GET_PRIV (page_data->mallard);
+
+    if (priv->state == MALLARD_STATE_STOP) {
+        mallard_page_data_cancel (page_data);
+        return;
+    }
+
+    mallard_page_data_cancel (page_data);
+
+    if (page_data->xmldoc)
+	xmlFreeDoc (page_data->xmldoc);
+    page_data->xmldoc = NULL;
+}
+
+static void
+transform_error (YelpTransform   *transform,
+                 MallardPageData *page_data)
+{
+    YelpMallardDocumentPrivate *priv;
+    GError *error;
+
+    g_assert (page_data != NULL && page_data->mallard != NULL &&
+              YELP_IS_MALLARD_DOCUMENT (page_data->mallard));
+    g_assert (transform == page_data->transform);
+
+    priv = GET_PRIV (page_data->mallard);
+
+    if (priv->state == MALLARD_STATE_STOP) {
+        mallard_page_data_cancel (page_data);
+        return;
+    }
+
+    error = yelp_transform_get_error (transform);
+    yelp_document_error_pending ((YelpDocument *) (page_data->mallard), error);
+    g_error_free (error);
+
+    mallard_page_data_cancel (page_data);
+}
diff --git a/libyelp/yelp-mallard-document.h b/libyelp/yelp-mallard-document.h
new file mode 100644
index 0000000..9bfb52a
--- /dev/null
+++ b/libyelp/yelp-mallard-document.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2009 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_MALLARD_DOCUMENT_H__
+#define __YELP_MALLARD_DOCUMENT_H__
+
+#include <glib-object.h>
+
+#include "yelp-document.h"
+
+#define YELP_TYPE_MALLARD_DOCUMENT         (yelp_mallard_document_get_type ())
+#define YELP_MALLARD_DOCUMENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_MALLARD_DOCUMENT, YelpMallardDocument))
+#define YELP_MALLARD_DOCUMENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_MALLARD_DOCUMENT, YelpMallardDocumentClass))
+#define YELP_IS_MALLARD_DOCUMENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_MALLARD_DOCUMENT))
+#define YELP_IS_MALLARD_DOCUMENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_MALLARD_DOCUMENT))
+#define YELP_MALLARD_DOCUMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_MALLARD_DOCUMENT, YelpMallardDocumentClass))
+
+typedef struct _YelpMallardDocument      YelpMallardDocument;
+typedef struct _YelpMallardDocumentClass YelpMallardDocumentClass;
+
+struct _YelpMallardDocument {
+    YelpDocument      parent;
+};
+
+struct _YelpMallardDocumentClass {
+    YelpDocumentClass parent_class;
+};
+
+GType           yelp_mallard_document_get_type     (void);
+YelpDocument *  yelp_mallard_document_new          (YelpUri  *uri);
+
+#endif /* __YELP_MALLARD_DOCUMENT_H__ */
diff --git a/libyelp/yelp-settings.c b/libyelp/yelp-settings.c
index b1cb232..58c945b 100644
--- a/libyelp/yelp-settings.c
+++ b/libyelp/yelp-settings.c
@@ -368,6 +368,28 @@ yelp_settings_set_colors (YelpSettings      *settings,
     g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
 }
 
+const gchar*
+yelp_settings_get_color_param (YelpSettingsColor color)
+{
+    static const gchar *params[YELP_SETTINGS_NUM_COLORS] = {
+	"theme.color.background",
+	"theme.color.text",
+	"theme.color.text_light",
+	"theme.color.link",
+	"theme.color.link_visted",
+	"theme.color.gray_background",
+	"theme.color.gray_border",
+	"theme.color.blue_background",
+	"theme.color.blue_border",
+	"theme.color.red_background",
+	"theme.color.red_border",
+	"theme.color.yellow_background",
+	"theme.color.yellow_border"
+    };
+    g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
+    return params[color];
+}
+
 /******************************************************************************/
 
 gchar *
@@ -525,6 +547,21 @@ yelp_settings_set_icons (YelpSettings     *settings,
     g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
 }
 
+const gchar *
+yelp_settings_get_icon_param (YelpSettingsIcon icon)
+{
+    static const gchar *params[YELP_SETTINGS_NUM_ICONS] = {
+	"theme.icon.admon.bug",
+	"theme.icon.admon.caution",
+	"theme.icon.admon.important",
+	"theme.icon.admon.note",
+	"theme.icon.admon.tip",
+	"theme.icon.admon.warning"
+    };
+    g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
+    return params[icon];
+}
+
 /******************************************************************************/
 
 static void
diff --git a/libyelp/yelp-settings.h b/libyelp/yelp-settings.h
index 000f5f8..c5bebe9 100644
--- a/libyelp/yelp-settings.h
+++ b/libyelp/yelp-settings.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Copyright (C) 2004-2009 Shaun McCance <shaunm gnome org>
  *
@@ -83,30 +83,33 @@ typedef enum {
 YelpSettings *      yelp_settings_get_default          (void);
 
 gchar *             yelp_settings_get_color            (YelpSettings       *settings,
-							YelpSettingsColor   color);
+                                                        YelpSettingsColor   color);
 gchar **            yelp_settings_get_colors           (YelpSettings       *settings);
 void                yelp_settings_set_colors           (YelpSettings       *settings,
-							YelpSettingsColor   first_color,
-							...);
+                                                        YelpSettingsColor   first_color,
+                                                        ...);
+const gchar*        yelp_settings_get_color_param      (YelpSettingsColor   color);
+
 
 gchar *             yelp_settings_get_font             (YelpSettings       *settings,
-							YelpSettingsFont    font);
+                                                        YelpSettingsFont    font);
 gchar *             yelp_settings_get_font_family      (YelpSettings       *settings,
-							YelpSettingsFont    font);
+                                                        YelpSettingsFont    font);
 gint                yelp_settings_get_font_size        (YelpSettings       *settings,
-							YelpSettingsFont    font);
+                                                        YelpSettingsFont    font);
 void                yelp_settings_set_fonts            (YelpSettings       *settings,
-							YelpSettingsFont    first_font,
-							...);
+                                                        YelpSettingsFont    first_font,
+                                                        ...);
 
 gint                yelp_settings_get_icon_size        (YelpSettings       *settings);
 void                yelp_settings_set_icon_size        (YelpSettings       *settings,
-							gint                size);
+                                                        gint                size);
 gchar *             yelp_settings_get_icon             (YelpSettings       *settings,
-							YelpSettingsIcon    icon);
+                                                        YelpSettingsIcon    icon);
 void                yelp_settings_set_icons            (YelpSettings       *settings,
-							YelpSettingsIcon    first_icon,
-							...);
+                                                        YelpSettingsIcon    first_icon,
+                                                        ...);
+const gchar *       yelp_settings_get_icon_param       (YelpSettingsIcon    icon);
 
 G_END_DECLS
 
diff --git a/libyelp/yelp-transform.c b/libyelp/yelp-transform.c
index 919b08a..8dfd27d 100644
--- a/libyelp/yelp-transform.c
+++ b/libyelp/yelp-transform.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
- * Copyright (C) 2003-2007 Shaun McCance  <shaunm gnome org>
+ * Copyright (C) 2003-2009 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
@@ -169,6 +169,8 @@ yelp_transform_dispose (GObject *object)
 
     /* FIXME */
     GHashTable             *chunks;
+
+    G_OBJECT_CLASS (yelp_transform_parent_class)->dispose (object);
 }
 
 static void
@@ -191,6 +193,8 @@ yelp_transform_finalize (GObject *object)
 
     g_strfreev (priv->params);
     g_mutex_free (priv->mutex);
+
+    G_OBJECT_CLASS (yelp_transform_parent_class)->finalize (object);
 }
 
 /******************************************************************************/
@@ -258,7 +262,7 @@ yelp_transform_start (YelpTransform       *transform,
                             BAD_CAST YELP_NAMESPACE,
                             (xsltTransformFunction) xslt_yelp_cache);
     xsltRegisterExtFunction (priv->context,
-                             BAD_CAST "aux",
+                             BAD_CAST "input",
                              BAD_CAST YELP_NAMESPACE,
                              (xmlXPathFunction) xslt_yelp_aux);
 
@@ -304,6 +308,20 @@ yelp_transform_cancel (YelpTransform *transform)
     g_mutex_unlock (priv->mutex);
 }
 
+GError *
+yelp_transform_get_error (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    GError *ret = NULL;
+
+    g_mutex_lock (priv->mutex);
+    if (priv->error)
+        ret = g_error_copy (priv->error);
+    g_mutex_unlock (priv->mutex);
+
+    return ret;
+}
+
 /******************************************************************************/
 
 static void
@@ -332,6 +350,8 @@ transform_chunk (YelpTransform *transform)
     YelpTransformPrivate *priv = GET_PRIV (transform);
     gchar *chunk_id;
 
+    debug_print (DB_FUNCTION, "entering\n");
+
     if (priv->cancelled)
         goto done;
 
diff --git a/libyelp/yelp-transform.h b/libyelp/yelp-transform.h
index 3c738bf..f0376c2 100644
--- a/libyelp/yelp-transform.h
+++ b/libyelp/yelp-transform.h
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
- * Copyright (C) 2003-2007 Shaun McCance  <shaunm gnome org>
+ * Copyright (C) 2003-2009 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
@@ -28,19 +28,6 @@
 #include <libxslt/xslt.h>
 #include <libxslt/transform.h>
 
-/*
-typedef enum {
-    YELP_TRANSFORM_CHUNK,
-    YELP_TRANSFORM_ERROR,
-    YELP_TRANSFORM_FINAL
-} YelpTransformSignal;
-
-typedef void  (*YelpTransformFunc)  (YelpTransform       *transform,
-				     YelpTransformSignal  signal,
-				     gpointer             func_data,
-				     gpointer             user_data);
-*/
-
 #define YELP_TYPE_TRANSFORM            (yelp_transform_get_type ())
 #define YELP_TRANSFORM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), YELP_TYPE_TRANSFORM, YelpTransform))
 #define YELP_TRANSFORM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), YELP_TYPE_TRANSFORM, YelpTransformClass))
@@ -69,5 +56,6 @@ gboolean         yelp_transform_start          (YelpTransform       *transform,
 gchar *          yelp_transform_take_chunk     (YelpTransform       *transform,
                                                 const gchar         *chunk_id);
 void             yelp_transform_cancel         (YelpTransform       *transform);
+GError *         yelp_transform_get_error      (YelpTransform       *transform);
 
 #endif /* __YELP_TRANSFORM_H__ */
diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c
index 8bf6436..9e9f220 100644
--- a/libyelp/yelp-view.c
+++ b/libyelp/yelp-view.c
@@ -29,6 +29,7 @@
 #include <gtk/gtk.h>
 #include <webkit/webkit.h>
 
+#include "yelp-debug.h"
 #include "yelp-error.h"
 #include "yelp-types.h"
 #include "yelp-view.h"
@@ -283,6 +284,8 @@ view_load_page (YelpView *view)
     YelpViewPrivate *priv = GET_PRIV (view);
     gchar *page_id;
 
+    debug_print (DB_FUNCTION, "entering\n");
+
     g_return_if_fail (priv->cancellable == NULL);
 
     if (priv->document == NULL) {
@@ -373,11 +376,13 @@ uri_resolved (YelpUri  *uri,
               YelpView *view)
 {
     YelpViewPrivate *priv = GET_PRIV (view);
-    YelpDocument *document = yelp_document_get_for_uri (uri);
+    YelpDocument *document;
+
+    debug_print (DB_FUNCTION, "entering\n");
 
+    document  = yelp_document_get_for_uri (uri);
     if (priv->document)
         g_object_unref (priv->document);
-
     priv->document = document;
 
     view_load_page (view);
@@ -391,15 +396,18 @@ document_callback (YelpDocument       *document,
 {
     YelpViewPrivate *priv = GET_PRIV (view);
 
+    debug_print (DB_FUNCTION, "entering\n");
+
     if (signal == YELP_DOCUMENT_SIGNAL_INFO) {
         /* FIXME */
     }
     else if (signal == YELP_DOCUMENT_SIGNAL_CONTENTS) {
-	const gchar *contents = yelp_document_read_contents (document, NULL);
+	const gchar *contents;
         gchar *real_uri, *mime_type, *page_id;
         real_uri = yelp_uri_get_canonical_uri (priv->uri);
         page_id = yelp_uri_get_page_id (priv->uri);
         mime_type = yelp_document_get_mime_type (document, page_id);
+        contents = yelp_document_read_contents (document, page_id);
         webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
                                      contents,
                                      mime_type,
diff --git a/tests/test-view.c b/tests/test-view.c
index 691af7d..b01d078 100644
--- a/tests/test-view.c
+++ b/tests/test-view.c
@@ -53,9 +53,8 @@ main (int argc, char **argv)
     YelpDocument *document;
     GCancellable *cancellable;
 
-    gtk_init (&argc, &argv);
-
     g_thread_init (NULL);
+    gtk_init (&argc, &argv);
 
     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
     gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);



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