summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun McCance <shaunm@gnome.org>2009-10-06 23:10:53 -0500
committerShaun McCance <shaunm@gnome.org>2009-10-06 23:10:53 -0500
commit0708e72ace823babfe0bc46c19221981baac70ab (patch)
tree741b2792b2044b284e2382cd099b71fcda18995d
parent88ad4966010f46623476f24a134d70dada4359d1 (diff)
downloadyelp-0708e72ace823babfe0bc46c19221981baac70ab.tar.gz
[yelp-uri] Resolve URIs asynchronously, no blocking IO
-rw-r--r--libyelp/yelp-document.c8
-rw-r--r--libyelp/yelp-settings.h6
-rw-r--r--libyelp/yelp-uri.c334
-rw-r--r--libyelp/yelp-uri.h23
-rw-r--r--libyelp/yelp-view.c109
-rw-r--r--tests/test-uri.c41
6 files changed, 377 insertions, 144 deletions
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index 1efcb906..d464d44d 100644
--- a/libyelp/yelp-document.c
+++ b/libyelp/yelp-document.c
@@ -117,13 +117,18 @@ yelp_document_get_for_uri (YelpUri *uri)
{
static GHashTable *documents = NULL;
gchar *base_uri;
- YelpDocument *document;
+ YelpDocument *document = NULL;
if (documents == NULL)
documents = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
+ g_return_val_if_fail (yelp_uri_is_resolved (uri), NULL);
+
base_uri = yelp_uri_get_base_uri (uri);
+ if (base_uri == NULL)
+ return NULL;
+
document = g_hash_table_lookup (documents, base_uri);
if (document != NULL) {
@@ -155,7 +160,6 @@ yelp_document_get_for_uri (YelpUri *uri)
case YELP_URI_DOCUMENT_TYPE_SEARCH:
/* FIXME */
break;
- case YELP_URI_DOCUMENT_TYPE_UNKNOWN:
case YELP_URI_DOCUMENT_TYPE_NOT_FOUND:
case YELP_URI_DOCUMENT_TYPE_EXTERNAL:
case YELP_URI_DOCUMENT_TYPE_ERROR:
diff --git a/libyelp/yelp-settings.h b/libyelp/yelp-settings.h
index 91a8e329..000f5f88 100644
--- a/libyelp/yelp-settings.h
+++ b/libyelp/yelp-settings.h
@@ -48,7 +48,7 @@ struct _YelpSettingsClass {
};
typedef enum {
- YELP_SETTINGS_COLOR_BASE = 0,
+ YELP_SETTINGS_COLOR_BASE,
YELP_SETTINGS_COLOR_TEXT,
YELP_SETTINGS_COLOR_TEXT_LIGHT,
YELP_SETTINGS_COLOR_LINK,
@@ -65,13 +65,13 @@ typedef enum {
} YelpSettingsColor;
typedef enum {
- YELP_SETTINGS_FONT_VARIABLE = 0,
+ YELP_SETTINGS_FONT_VARIABLE,
YELP_SETTINGS_FONT_FIXED,
YELP_SETTINGS_NUM_FONTS
} YelpSettingsFont;
typedef enum {
- YELP_SETTINGS_ICON_BUG = 0,
+ YELP_SETTINGS_ICON_BUG,
YELP_SETTINGS_ICON_CAUTION,
YELP_SETTINGS_ICON_IMPORTANT,
YELP_SETTINGS_ICON_NOTE,
diff --git a/libyelp/yelp-uri.c b/libyelp/yelp-uri.c
index 5b6de6e3..b8d157a5 100644
--- a/libyelp/yelp-uri.c
+++ b/libyelp/yelp-uri.c
@@ -37,24 +37,22 @@ static void yelp_uri_init (YelpUri *uri);
static void yelp_uri_dispose (GObject *object);
static void yelp_uri_finalize (GObject *object);
-static void resolve_file_uri (YelpUri *ret,
- const gchar *arg);
-static void resolve_file_path (YelpUri *ret,
- YelpUri *base,
- const gchar *arg);
-static void resolve_data_dirs (YelpUri *ret,
+static void resolve_async (YelpUri *uri);
+static gboolean resolve_final (YelpUri *uri);
+
+static void resolve_file_uri (YelpUri *uri);
+static void resolve_file_path (YelpUri *uri);
+static void resolve_data_dirs (YelpUri *uri,
const gchar **subdirs,
const gchar *docid,
const gchar *pageid);
-static void resolve_ghelp_uri (YelpUri *ret,
- const gchar *arg);
-static void resolve_man_uri (YelpUri *ret,
- const gchar *arg);
-static void resolve_info_uri (YelpUri *ret,
- const gchar *arg);
-static void resolve_page_and_frag (YelpUri *ret,
+static void resolve_ghelp_uri (YelpUri *uri);
+static void resolve_man_uri (YelpUri *uri);
+static void resolve_info_uri (YelpUri *uri);
+static void resolve_page_and_frag (YelpUri *uri,
const gchar *arg);
-static void resolve_common (YelpUri *ret);
+static void resolve_common (YelpUri *uri);
+
static gboolean is_man_path (const gchar *uri,
const gchar *encoding);
@@ -63,13 +61,27 @@ G_DEFINE_TYPE (YelpUri, yelp_uri, G_TYPE_OBJECT);
typedef struct _YelpUriPrivate YelpUriPrivate;
struct _YelpUriPrivate {
+ GThread *resolver;
+
YelpUriDocumentType doctype;
+ YelpUriDocumentType tmptype;
+
GFile *gfile;
gchar **search_path;
gchar *page_id;
gchar *frag_id;
+
+ /* Unresolved */
+ YelpUri *res_base;
+ gchar *res_arg;
};
+enum {
+ RESOLVED,
+ LAST_SIGNAL
+};
+static guint uri_signals[LAST_SIGNAL] = {0,};
+
/******************************************************************************/
static const gchar *mancats[] = {
@@ -96,6 +108,14 @@ yelp_uri_class_init (YelpUriClass *klass)
object_class->dispose = yelp_uri_dispose;
object_class->finalize = yelp_uri_finalize;
+ uri_signals[RESOLVED] =
+ g_signal_new ("resolved",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
g_type_class_add_private (klass, sizeof (YelpUriPrivate));
}
@@ -115,6 +135,11 @@ yelp_uri_dispose (GObject *object)
priv->gfile = NULL;
}
+ if (priv->res_base) {
+ g_object_unref (priv->res_base);
+ priv->res_base = NULL;
+ }
+
G_OBJECT_CLASS (yelp_uri_parent_class)->dispose (object);
}
@@ -126,6 +151,7 @@ yelp_uri_finalize (GObject *object)
g_strfreev (priv->search_path);
g_free (priv->page_id);
g_free (priv->frag_id);
+ g_free (priv->res_arg);
G_OBJECT_CLASS (yelp_uri_parent_class)->finalize (object);
}
@@ -133,11 +159,104 @@ yelp_uri_finalize (GObject *object)
/******************************************************************************/
YelpUri *
-yelp_uri_resolve (const gchar *arg)
+yelp_uri_new (const gchar *arg)
+{
+ return yelp_uri_new_relative (NULL, arg);
+}
+
+YelpUri *
+yelp_uri_new_relative (YelpUri *base, const gchar *arg)
+{
+ YelpUri *uri;
+ YelpUriPrivate *priv;
+
+ uri = (YelpUri *) g_object_new (YELP_TYPE_URI, NULL);
+
+ priv = GET_PRIV (uri);
+ priv->doctype = YELP_URI_DOCUMENT_TYPE_UNRESOLVED;
+ if (base)
+ priv->res_base = g_object_ref (base);
+ priv->res_arg = g_strdup (arg);
+
+ return uri;
+}
+
+/******************************************************************************/
+
+void
+yelp_uri_resolve (YelpUri *uri)
+{
+ YelpUriPrivate *priv = GET_PRIV (uri);
+ if (priv->resolver == NULL)
+ priv->resolver = g_thread_create ((GThreadFunc) resolve_async,
+ uri, FALSE, NULL);
+}
+
+/* We want code to be able to do something like this:
+ *
+ * if (yelp_uri_get_document_type (uri) != YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
+ * g_signal_connect (uri, "resolve", callback, data);
+ * yelp_uri_resolve (uri);
+ * }
+ *
+ * Resolving happens in a separate thread, though, so if that thread can change
+ * the document type, we have a race condition. So here's the rules we play by:
+ *
+ * 1) None of the getters except the document type getter can return real data
+ * while the URI is unresolved. They all do a resolved check first, and
+ * return NULL if the URI is not resolved.
+ *
+ * 2) The threaded resolver functions can modify anything but the document
+ * type. They are the only things that are allowed to modify that data.
+ *
+ * 3) The resolver thread is not allowed to modify the document type. When
+ * it's done, it queues an async function to set the document type and
+ * emit "resolved" in the main thread.
+ *
+ * 4) Once a URI is resolved, it is immutable.
+ */
+static void
+resolve_async (YelpUri *uri)
+{
+ YelpUriPrivate *priv = GET_PRIV (uri);
+
+ if (g_str_has_prefix (priv->res_arg, "ghelp:")
+ || g_str_has_prefix (priv->res_arg, "gnome-help:")) {
+ resolve_ghelp_uri (uri);
+ }
+ else if (g_str_has_prefix (priv->res_arg, "file:")) {
+ resolve_file_uri (uri);
+ }
+ else if (g_str_has_prefix (priv->res_arg, "man:")) {
+ resolve_man_uri (uri);
+ }
+ else if (g_str_has_prefix (priv->res_arg, "info:")) {
+ resolve_info_uri (uri);
+ }
+ else {
+ resolve_file_path (uri);
+ }
+
+ g_idle_add ((GSourceFunc) resolve_final, uri);
+}
+
+static gboolean
+resolve_final (YelpUri *uri)
{
- return yelp_uri_resolve_relative (NULL, arg);
+ YelpUriPrivate *priv = GET_PRIV (uri);
+
+ priv->resolver = NULL;
+
+ if (priv->tmptype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
+ priv->doctype = priv->tmptype;
+ else
+ priv->doctype = YELP_URI_DOCUMENT_TYPE_ERROR;
+
+ g_signal_emit (uri, uri_signals[RESOLVED], 0);
+ return FALSE;
}
+/*
YelpUri *
yelp_uri_resolve_relative (YelpUri *base, const gchar *arg)
{
@@ -148,18 +267,6 @@ yelp_uri_resolve_relative (YelpUri *base, const gchar *arg)
priv = GET_PRIV (ret);
priv->doctype = YELP_URI_DOCUMENT_TYPE_UNKNOWN;
- if (g_str_has_prefix (arg, "ghelp:") || g_str_has_prefix (arg, "gnome-help:")) {
- resolve_ghelp_uri (ret, arg);
- }
- else if (g_str_has_prefix (arg, "file:")) {
- resolve_file_uri (ret, arg);
- }
- else if (g_str_has_prefix (arg, "man:")) {
- resolve_man_uri (ret, arg);
- }
- else if (g_str_has_prefix (arg, "info:")) {
- resolve_info_uri (ret, arg);
- }
else if (strchr (arg, ':')) {
priv->doctype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
priv->gfile = g_file_new_for_uri (arg);
@@ -171,6 +278,16 @@ yelp_uri_resolve_relative (YelpUri *base, const gchar *arg)
return ret;
}
+*/
+
+/******************************************************************************/
+
+gboolean
+yelp_uri_is_resolved (YelpUri *uri)
+{
+ YelpUriPrivate *priv = GET_PRIV (uri);
+ return priv->doctype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED;
+}
YelpUriDocumentType
yelp_uri_get_document_type (YelpUri *uri)
@@ -183,6 +300,8 @@ gchar *
yelp_uri_get_base_uri (YelpUri *uri)
{
YelpUriPrivate *priv = GET_PRIV (uri);
+ if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
+ return NULL;
return priv->gfile ? g_file_get_uri (priv->gfile) : NULL;
}
@@ -190,6 +309,8 @@ gchar **
yelp_uri_get_search_path (YelpUri *uri)
{
YelpUriPrivate *priv = GET_PRIV (uri);
+ if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
+ return NULL;
return g_strdupv (priv->search_path);
}
@@ -197,6 +318,8 @@ gchar *
yelp_uri_get_page_id (YelpUri *uri)
{
YelpUriPrivate *priv = GET_PRIV (uri);
+ if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
+ return NULL;
return g_strdup (priv->page_id);
}
@@ -204,50 +327,55 @@ gchar *
yelp_uri_get_frag_id (YelpUri *uri)
{
YelpUriPrivate *priv = GET_PRIV (uri);
+ if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
+ return NULL;
return g_strdup (priv->frag_id);
}
/******************************************************************************/
static void
-resolve_file_uri (YelpUri *ret, const gchar *arg)
+resolve_file_uri (YelpUri *uri)
{
- YelpUriPrivate *priv = GET_PRIV (ret);
- gchar *uri;
- const gchar *hash = strchr (arg, '#');
+ YelpUriPrivate *priv = GET_PRIV (uri);
+ gchar *uristr;
+ const gchar *hash = strchr (priv->res_arg, '#');
if (hash)
- uri = g_strndup (arg, hash - arg);
+ uristr = g_strndup (priv->res_arg, hash - priv->res_arg);
else
- uri = (gchar *) arg;
+ uristr = priv->res_arg;
- priv->gfile = g_file_new_for_uri (uri);
+ priv->gfile = g_file_new_for_uri (uristr);
if (hash) {
- resolve_page_and_frag (ret, hash + 1);
- g_free (uri);
+ resolve_page_and_frag (uri, hash + 1);
+ g_free (uristr);
}
- resolve_common (ret);
+ resolve_common (uri);
}
static void
-resolve_file_path (YelpUri *ret, YelpUri *base, const gchar *arg)
+resolve_file_path (YelpUri *uri)
{
- YelpUriPrivate *base_priv = GET_PRIV (base);
- YelpUriPrivate *priv = GET_PRIV (ret);
+ YelpUriPrivate *base_priv;
+ YelpUriPrivate *priv = GET_PRIV (uri);
gchar *path;
- const gchar *hash = strchr (arg, '#');
+ const gchar *hash = strchr (priv->res_arg, '#');
+
+ if (priv->res_base)
+ base_priv = GET_PRIV (priv->res_base);
if (hash)
- path = g_strndup (arg, hash - arg);
+ path = g_strndup (priv->res_arg, hash - priv->res_arg);
else
- path = (gchar *) arg;
+ path = priv->res_arg;
- if (arg[0] == '/') {
+ if (priv->res_arg[0] == '/') {
priv->gfile = g_file_new_for_path (path);
}
- else if (base && base_priv->gfile) {
+ else if (base_priv->gfile) {
priv->gfile = g_file_resolve_relative_path (base_priv->gfile, path);
}
else {
@@ -261,11 +389,11 @@ resolve_file_path (YelpUri *ret, YelpUri *base, const gchar *arg)
}
if (hash) {
- resolve_page_and_frag (ret, hash + 1);
+ resolve_page_and_frag (uri, hash + 1);
g_free (path);
}
- resolve_common (ret);
+ resolve_common (uri);
}
static void
@@ -281,7 +409,6 @@ resolve_data_dirs (YelpUri *ret,
gchar **searchpath = NULL;
gint searchi, searchmax;
gint datadir_i, subdir_i, lang_i;
- YelpUriDocumentType type = YELP_URI_DOCUMENT_TYPE_UNKNOWN;
searchi = 0;
searchmax = 10;
@@ -304,13 +431,13 @@ resolve_data_dirs (YelpUri *ret,
searchpath[searchi] = helpdir;
searchpath[++searchi] = NULL;
- if (type != YELP_URI_DOCUMENT_TYPE_UNKNOWN)
+ if (priv->tmptype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
/* We've already found it. We're just adding to the search path now. */
continue;
filename = g_strdup_printf ("%s/index.page", helpdir);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
- type = YELP_URI_DOCUMENT_TYPE_MALLARD;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
g_free (filename);
filename = g_strdup (helpdir);
continue;
@@ -319,14 +446,14 @@ resolve_data_dirs (YelpUri *ret,
filename = g_strdup_printf ("%s/%s.xml", helpdir, pageid);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
- type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
continue;
}
g_free (filename);
filename = g_strdup_printf ("%s/%s.html", helpdir, pageid);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
- type = YELP_URI_DOCUMENT_TYPE_HTML;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_HTML;
continue;
}
g_free (filename);
@@ -334,31 +461,30 @@ resolve_data_dirs (YelpUri *ret,
} /* end for subdirs */
} /* end for datadirs */
- if (type == YELP_URI_DOCUMENT_TYPE_UNKNOWN) {
+ if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
g_strfreev (searchpath);
- priv->doctype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
}
else {
- priv->doctype = type;
priv->gfile = g_file_new_for_path (filename);
priv->search_path = searchpath;
}
}
static void
-resolve_ghelp_uri (YelpUri *ret, const gchar *arg)
+resolve_ghelp_uri (YelpUri *uri)
{
/* ghelp:/path/to/file
* ghelp:document
*/
- YelpUriPrivate *priv = GET_PRIV (ret);
+ YelpUriPrivate *priv = GET_PRIV (uri);
const gchar const *helpdirs[3] = {"help", "gnome/help", NULL};
gchar *docid = NULL;
gchar *colon, *hash, *slash, *pageid; /* do not free */
- colon = strchr (arg, ':');
+ colon = strchr (priv->res_arg, ':');
if (!colon) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_ERROR;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
return;
}
@@ -366,8 +492,9 @@ resolve_ghelp_uri (YelpUri *ret, const gchar *arg)
if (*colon == '/') {
gchar *newuri;
newuri = g_strdup_printf ("file:%s", colon);
- resolve_file_uri (ret, newuri);
- g_free (newuri);
+ g_free (priv->res_arg);
+ priv->res_arg = newuri;
+ resolve_file_uri (uri);
return;
}
@@ -375,7 +502,7 @@ resolve_ghelp_uri (YelpUri *ret, const gchar *arg)
if (!hash)
hash = strchr (colon, '#');
if (hash) {
- resolve_page_and_frag (ret, hash + 1);
+ resolve_page_and_frag (uri, hash + 1);
docid = g_strndup (colon, hash - colon);
}
else {
@@ -391,14 +518,14 @@ resolve_ghelp_uri (YelpUri *ret, const gchar *arg)
pageid = docid;
}
- resolve_data_dirs (ret, helpdirs, docid, pageid);
+ resolve_data_dirs (uri, helpdirs, docid, pageid);
/* Specifying pages and anchors for Mallard documents with ghelp URIs is sort
- hacked on. This is a touch inconsistent, but it maintains compatibility
+ of hacked on. This is a touch inconsistent, but it maintains compatibility
with the way things worked in 2.28, and ghelp URIs should be entering
compatibility-only mode.
*/
- if (priv->doctype == YELP_URI_DOCUMENT_TYPE_MALLARD && pageid != docid) {
+ if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_MALLARD && pageid != docid) {
if (priv->page_id)
g_free (priv->page_id);
priv->page_id = g_strdup (pageid);
@@ -408,9 +535,9 @@ resolve_ghelp_uri (YelpUri *ret, const gchar *arg)
}
static void
-resolve_man_uri (YelpUri *ret, const gchar *arg)
+resolve_man_uri (YelpUri *uri)
{
- YelpUriPrivate *priv = GET_PRIV (ret);
+ YelpUriPrivate *priv = GET_PRIV (uri);
/* man:/path/to/file
* man:name(section)
* man:name.section
@@ -429,12 +556,13 @@ resolve_man_uri (YelpUri *ret, const gchar *arg)
gchar *rbrace = NULL;
gint i, j, k;
- if (g_str_has_prefix (arg, "man:/")) {
+ if (g_str_has_prefix (priv->res_arg, "man:/")) {
gchar *newuri;
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
- newuri = g_strdup_printf ("file:%s", arg + 4);
- resolve_file_uri (ret, newuri);
- g_free (newuri);
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
+ newuri = g_strdup_printf ("file:%s", priv->res_arg + 4);
+ g_free (priv->res_arg);
+ priv->res_arg = newuri;
+ resolve_file_uri (uri);
return;
}
@@ -446,11 +574,11 @@ resolve_man_uri (YelpUri *ret, const gchar *arg)
manpath = g_strsplit (env, ":", 0);
}
- colon = strchr (arg, ':');
+ colon = strchr (priv->res_arg, ':');
if (colon)
colon++;
else
- colon = (gchar *) arg;
+ colon = (gchar *) priv->res_arg;
hash = strchr (colon, '#');
if (hash)
@@ -541,30 +669,30 @@ resolve_man_uri (YelpUri *ret, const gchar *arg)
}
if (fullpath) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
priv->gfile = g_file_new_for_path (fullpath);
- resolve_common (ret);
+ resolve_common (uri);
g_free (fullpath);
} else {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
}
if (hash)
- resolve_page_and_frag (ret, hash + 1);
+ resolve_page_and_frag (uri, hash + 1);
g_free (newarg);
}
static void
-resolve_info_uri (YelpUri *ret, const gchar *arg)
+resolve_info_uri (YelpUri *uri)
{
/* FIXME */
}
static void
-resolve_page_and_frag (YelpUri *ret, const gchar *arg)
+resolve_page_and_frag (YelpUri *uri, const gchar *arg)
{
- YelpUriPrivate *priv = GET_PRIV (ret);
+ YelpUriPrivate *priv = GET_PRIV (uri);
gchar *hash;
if (!arg || arg[0] == '\0')
@@ -582,9 +710,9 @@ resolve_page_and_frag (YelpUri *ret, const gchar *arg)
}
static void
-resolve_common (YelpUri *ret)
+resolve_common (YelpUri *uri)
{
- YelpUriPrivate *priv = GET_PRIV (ret);
+ YelpUriPrivate *priv = GET_PRIV (uri);
GFileInfo *info;
GError *error = NULL;
@@ -595,9 +723,9 @@ resolve_common (YelpUri *ret)
NULL, &error);
if (error) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
else
- priv->doctype = YELP_URI_DOCUMENT_TYPE_ERROR;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
g_error_free (error);
return;
}
@@ -615,10 +743,10 @@ resolve_common (YelpUri *ret)
}
}
- if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNKNOWN) {
+ if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) ==
G_FILE_TYPE_DIRECTORY) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MALLARD;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
}
else {
gchar *basename;
@@ -628,48 +756,48 @@ resolve_common (YelpUri *ret)
if (g_str_equal (mime_type, "text/xml") ||
g_str_equal (mime_type, "application/docbook+xml") ||
g_str_equal (mime_type, "application/xml")) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
}
else if (g_str_equal (mime_type, "text/html")) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_HTML;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_HTML;
}
else if (g_str_equal (mime_type, "application/xhtml+xml")) {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_XHTML;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_XHTML;
}
else if (g_str_equal (mime_type, "application/x-gzip")) {
if (g_str_has_suffix (basename, ".info.gz"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_INFO;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
else if (is_man_path (basename, "gz"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
}
else if (g_str_equal (mime_type, "application/x-bzip")) {
if (g_str_has_suffix (basename, ".info.bz2"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_INFO;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
else if (is_man_path (basename, "bz2"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
}
else if (g_str_equal (mime_type, "application/x-lzma")) {
if (g_str_has_suffix (basename, ".info.lzma"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_INFO;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
else if (is_man_path (basename, "lzma"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
}
else if (g_str_equal (mime_type, "application/octet-stream")) {
if (g_str_has_suffix (basename, ".info"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_INFO;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
else if (is_man_path (basename, NULL))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
}
else if (g_str_equal (mime_type, "text/plain")) {
if (g_str_has_suffix (basename, ".info"))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_INFO;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
else if (is_man_path (basename, NULL))
- priv->doctype = YELP_URI_DOCUMENT_TYPE_MAN;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
else
- priv->doctype = YELP_URI_DOCUMENT_TYPE_TEXT;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_TEXT;
}
else {
- priv->doctype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
+ priv->tmptype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
}
}
}
diff --git a/libyelp/yelp-uri.h b/libyelp/yelp-uri.h
index 2a6f144f..b44d2c83 100644
--- a/libyelp/yelp-uri.h
+++ b/libyelp/yelp-uri.h
@@ -38,7 +38,7 @@ typedef struct _YelpUri YelpUri;
typedef struct _YelpUriClass YelpUriClass;
typedef enum {
- YELP_URI_DOCUMENT_TYPE_UNKNOWN = 0,
+ YELP_URI_DOCUMENT_TYPE_UNRESOLVED,
YELP_URI_DOCUMENT_TYPE_DOCBOOK,
YELP_URI_DOCUMENT_TYPE_MALLARD,
YELP_URI_DOCUMENT_TYPE_MAN,
@@ -62,17 +62,20 @@ struct _YelpUriClass {
};
-GType yelp_uri_get_type (void);
+GType yelp_uri_get_type (void);
-YelpUri * yelp_uri_resolve (const gchar *arg);
-YelpUri * yelp_uri_resolve_relative (YelpUri *base,
- const gchar *arg);
+YelpUri * yelp_uri_new (const gchar *arg);
+YelpUri * yelp_uri_new_relative (YelpUri *base,
+ const gchar *arg);
-YelpUriDocumentType yelp_uri_get_document_type (YelpUri *uri);
-gchar * yelp_uri_get_base_uri (YelpUri *uri);
-gchar ** yelp_uri_get_search_path (YelpUri *uri);
-gchar * yelp_uri_get_page_id (YelpUri *uri);
-gchar * yelp_uri_get_frag_id (YelpUri *uri);
+void yelp_uri_resolve (YelpUri *uri);
+
+gboolean yelp_uri_is_resolved (YelpUri *uri);
+YelpUriDocumentType yelp_uri_get_document_type (YelpUri *uri);
+gchar * yelp_uri_get_base_uri (YelpUri *uri);
+gchar ** yelp_uri_get_search_path (YelpUri *uri);
+gchar * yelp_uri_get_page_id (YelpUri *uri);
+gchar * yelp_uri_get_frag_id (YelpUri *uri);
G_END_DECLS
diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c
index f77c74d4..36f4ed53 100644
--- a/libyelp/yelp-view.c
+++ b/libyelp/yelp-view.c
@@ -46,9 +46,13 @@ static void yelp_view_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec);
+static void view_clear_load (YelpView *view);
+static void view_load_page (YelpView *view);
static void view_show_error_page (YelpView *view,
GError *error);
+static void uri_resolved (YelpUri *uri,
+ YelpView *view);
static void document_callback (YelpDocument *document,
YelpDocumentSignal signal,
YelpView *view,
@@ -71,6 +75,7 @@ G_DEFINE_TYPE (YelpView, yelp_view, WEBKIT_TYPE_WEB_VIEW);
typedef struct _YelpViewPrivate YelpViewPrivate;
struct _YelpViewPrivate {
YelpUri *uri;
+ gulong uri_resolved;
YelpDocument *document;
GCancellable *cancellable;
@@ -203,7 +208,7 @@ void
yelp_view_load (YelpView *view,
const gchar *uri)
{
- YelpUri *yuri = yelp_uri_resolve (uri);
+ YelpUri *yuri = yelp_uri_new (uri);
yelp_view_load_uri (view, yuri);
g_object_unref (yuri);
}
@@ -212,12 +217,21 @@ void
yelp_view_load_uri (YelpView *view,
YelpUri *uri)
{
- YelpDocument *document = yelp_document_get_for_uri (uri);
+ YelpViewPrivate *priv = GET_PRIV (view);
- yelp_view_load_document (view, uri, document);
+ view_clear_load (view);
+ g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
- if (document)
- g_object_unref (document);
+ priv->uri = g_object_ref (uri);
+ if (!yelp_uri_is_resolved (uri)) {
+ priv->uri_resolved = g_signal_connect (uri, "resolved",
+ G_CALLBACK (uri_resolved),
+ view);
+ yelp_uri_resolve (uri);
+ }
+ else {
+ uri_resolved (uri, view);
+ }
}
void
@@ -226,28 +240,74 @@ yelp_view_load_document (YelpView *view,
YelpDocument *document)
{
YelpViewPrivate *priv = GET_PRIV (view);
- gchar *page_id;
+ g_return_if_fail (yelp_uri_is_resolved (uri));
+
+ view_clear_load (view);
g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
- if (!document) {
+ priv->uri = g_object_ref (uri);
+ g_object_ref (document);
+ if (priv->document)
+ g_object_unref (document);
+ priv->document = document;
+
+ view_load_page (view);
+}
+
+/******************************************************************************/
+
+static void
+view_clear_load (YelpView *view)
+{
+ YelpViewPrivate *priv = GET_PRIV (view);
+
+ if (priv->uri) {
+ if (priv->uri_resolved != 0) {
+ g_signal_handler_disconnect (priv->uri, priv->uri_resolved);
+ priv->uri_resolved = 0;
+ }
+ g_object_unref (priv->uri);
+ priv->uri = NULL;
+ }
+
+ if (priv->cancellable) {
+ g_cancellable_cancel (priv->cancellable);
+ priv->cancellable = NULL;
+ }
+}
+
+static void
+view_load_page (YelpView *view)
+{
+ YelpViewPrivate *priv = GET_PRIV (view);
+ gchar *page_id;
+
+ g_return_if_fail (priv->cancellable == NULL);
+
+ if (priv->document == NULL) {
GError *error;
gchar *base_uri;
- base_uri = yelp_uri_get_base_uri (uri);
+ /* FIXME: and if priv->uri is NULL? */
+ base_uri = yelp_uri_get_base_uri (priv->uri);
/* FIXME: CANT_READ isn't right */
- error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
- _("Could not load a document for ā€˜%sā€™"),
- base_uri);
- g_free (base_uri);
+ if (base_uri) {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
+ _("Could not load a document for ā€˜%sā€™"),
+ base_uri);
+ g_free (base_uri);
+ }
+ else {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
+ _("Could not load a document"));
+ }
view_show_error_page (view, error);
return;
}
- page_id = yelp_uri_get_page_id (uri);
- priv->uri = g_object_ref (uri);
+ page_id = yelp_uri_get_page_id (priv->uri);
priv->cancellable = g_cancellable_new ();
- priv->document = g_object_ref (document);
- yelp_document_request_page (document,
+ yelp_document_request_page (priv->document,
page_id,
priv->cancellable,
(YelpDocumentCallback) document_callback,
@@ -306,6 +366,23 @@ view_show_error_page (YelpView *view,
g_free (page);
}
+/******************************************************************************/
+
+static void
+uri_resolved (YelpUri *uri,
+ YelpView *view)
+{
+ YelpViewPrivate *priv = GET_PRIV (view);
+ YelpDocument *document = yelp_document_get_for_uri (uri);
+
+ if (priv->document)
+ g_object_unref (priv->document);
+
+ priv->document = document;
+
+ view_load_page (view);
+}
+
static void
document_callback (YelpDocument *document,
YelpDocumentSignal signal,
diff --git a/tests/test-uri.c b/tests/test-uri.c
index 73f44dfd..96f9d5e2 100644
--- a/tests/test-uri.c
+++ b/tests/test-uri.c
@@ -25,9 +25,12 @@
#include <string.h>
#include <gio/gio.h>
+#include <gio/gunixoutputstream.h>
#include "yelp-uri.h"
+GMainLoop *loop;
+
static void
print_uri (YelpUri *uri, GOutputStream *stream)
{
@@ -70,8 +73,8 @@ print_uri (YelpUri *uri, GOutputStream *stream)
case YELP_URI_DOCUMENT_TYPE_ERROR:
type = "ERROR";
break;
- case YELP_URI_DOCUMENT_TYPE_UNKNOWN:
- type = "UNKNOWN";
+ case YELP_URI_DOCUMENT_TYPE_UNRESOLVED:
+ type = "UNRESOLVED";
break;
}
@@ -135,7 +138,13 @@ static void run_test (gconstpointer data)
NULL, NULL));
newline = strchr (contents, '\n');
curi = g_strndup (contents, newline - contents);
- uri = yelp_uri_resolve (curi);
+ uri = yelp_uri_new (curi);
+ yelp_uri_resolve (uri);
+
+ while (!yelp_uri_is_resolved (uri))
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+
outstream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
print_uri (uri, outstream);
out = (gchar *) g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (outstream));
@@ -174,6 +183,15 @@ run_all_tests (int argc, char **argv)
return g_test_run ();
}
+static void
+uri_resolved (YelpUri *uri)
+{
+ GOutputStream *stream = g_unix_output_stream_new (1, FALSE);
+ print_uri (uri, stream);
+ g_object_unref (uri);
+ g_main_loop_quit (loop);
+}
+
int
main (int argc, char **argv)
{
@@ -181,28 +199,31 @@ main (int argc, char **argv)
YelpUri *uri = NULL;
g_type_init ();
+ g_thread_init (NULL);
g_log_set_always_fatal (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
- g_test_init (&argc, &argv);
if (argc < 2) {
+ g_test_init (&argc, &argv, NULL);
return run_all_tests (argc, argv);
}
else {
if (argc > 2) {
- parent = yelp_uri_resolve (argv[1]);
- uri = yelp_uri_resolve_relative (parent, argv[2]);
+ parent = yelp_uri_new (argv[1]);
+ uri = yelp_uri_new_relative (parent, argv[2]);
} else {
- uri = yelp_uri_resolve (argv[1]);
+ uri = yelp_uri_new (argv[1]);
}
if (uri) {
- GOutputStream *stream = g_unix_output_stream_new (1, FALSE);
- print_uri (uri, stream);
- g_object_unref (uri);
+ g_signal_connect (uri, "resolved", G_CALLBACK (uri_resolved), NULL);
+ yelp_uri_resolve (uri);
}
if (parent) {
g_object_unref (parent);
}
}
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+
return 0;
}