netsurf: branch chris/gadtools-53-5 updated. release/3.0-194-gd83b3bf

NetSurf Browser Project (Commit Mailer) no-reply at netsurf-browser.org
Thu Jun 6 20:35:05 BST 2013


Gitweb links:

...log http://git.netsurf-browser.org/netsurf.git/shortlog/d83b3bf6465b49f2e171038aebd822cd2d67698b
...commit http://git.netsurf-browser.org/netsurf.git/commit/d83b3bf6465b49f2e171038aebd822cd2d67698b
...tree http://git.netsurf-browser.org/netsurf.git/tree/d83b3bf6465b49f2e171038aebd822cd2d67698b

The branch, chris/gadtools-53-5 has been updated
       via  d83b3bf6465b49f2e171038aebd822cd2d67698b (commit)
       via  96e8990faf6927663198c27bb075e03370681c8f (commit)
       via  fde868b81c687eb48cd44aff1b81184008729a82 (commit)
       via  4bd65d429cb68bb1927fe4f3e6de2112d61f8114 (commit)
       via  8427871f8a489f69ddab3717a1cb198a6376bd30 (commit)
       via  4d39d4314c48e54bf14ba1edb53c82e6c6d1712e (commit)
       via  4e248695248d2c749b2d9e892549ba0e9390a3d0 (commit)
       via  ccb0c1cfd19f72bdf3118161e61a37829c160afc (commit)
       via  3aba4b778aa416c7a8e86f85610dbf4efb758555 (commit)
       via  8d57bb30af6e5f72664c1176155c55ed7198f60e (commit)
       via  6397fedb2b221aab93d697ed9fc0530dd1415233 (commit)
       via  ae6058c15c4dbf1c067fac45cd092afeefa68a53 (commit)
       via  f2a6d645ae24ab49828d2d0ceb672bb7a80501c2 (commit)
       via  f31ab148cb99cb83a919046fd74f3895589b6878 (commit)
       via  94dc0795c1b59476c50da3f4d8861675a37fcb33 (commit)
       via  bccaa05fdb50a1d5f481cf34f6af906638dfc68c (commit)
       via  9bd296987684788c32dd346b2d67671ed5dfe7a0 (commit)
       via  31e3b27fad73dc5424017d55f918b383502d5d0e (commit)
       via  9ad5b98fcda6e99007741d80ad29674c3b26bc77 (commit)
       via  40682a899e157969a67062430a87cf43cacd1186 (commit)
       via  3b971bb1a7883b4eaee965e65daa58d0258caed5 (commit)
       via  173bfe3d3dd3d29a6fe37f9f6db542494dfe3f35 (commit)
       via  8179e51a758843949987dc3e4a89dbeaf619a149 (commit)
       via  fe78657b081c68d4e82ce0d526defaefbe1a0677 (commit)
       via  0bb08cc5d2a2c66b77c3ec19db244c57a270a009 (commit)
       via  8b586b2d67dad1f7d874091664ab582936e15dc4 (commit)
       via  864762cbe60d04ba978ddbd9bf125240dd26f631 (commit)
       via  9b39408dffe09940589c2f00026c0e605d836b78 (commit)
       via  ac1865f36181d3b25045d0ab284b70b697b6a2ed (commit)
       via  b2aa0c129c73201b7e1e466d9996e5e491464592 (commit)
       via  e2056974ca152a9c2cd14545bc610546c59264cc (commit)
       via  22ce03aed6e011a53a8adbbbf2cf4df798d8cc45 (commit)
       via  817e85f8823f6847b49c39622b6d62ac86871391 (commit)
       via  ec3491280a67ea55d322baf736d538815a4a6087 (commit)
       via  92d6c14c8dfd7b4978deca602d51d3afbbfdcfe7 (commit)
       via  44badddbdfabac0b4c5ca8737f4152f5aca25b89 (commit)
       via  a4f67018faf7755d077778b750524f3a7555f5c7 (commit)
       via  44f91c9fc8befb67211949008121cb0eae6de562 (commit)
       via  4de556b6f5206884d14cdca30c1816605fd8213f (commit)
       via  42bbc16fa87cd0e5f11cf41f776ad5700de0a167 (commit)
       via  68c2013504b9ed951178dd8c77ba479f1b134614 (commit)
       via  8e8b4fbe574c72b467054d0c64b8ca28d98bbadd (commit)
       via  1bbafde641f05068c50b0c4ccd3ee0ec4a5c69d9 (commit)
       via  2d483113ef9dac00c7fbe7548a9aa37248c14803 (commit)
       via  06d87fec2b7e7dae2bfad7a23692451feb1cd814 (commit)
       via  2dec72b4d55b3e728a8582d7055584ecabfb8010 (commit)
       via  45d309c0e3020afd785e4342cde7893b4afccd2a (commit)
       via  9d00f63ff4fabdc7f446b51edfcb79719fd648a9 (commit)
       via  cbe8d1c125b2f3ffa7693673f19d8efda3e6f333 (commit)
       via  4e5d478ed157dd7a61d61c9d079b59c439af777e (commit)
       via  a88fb2e0e834784af2dcc5f9c530fc853477d4c4 (commit)
       via  f3065a5cfdacf0d7e1f379ecd31cd256f42c9dd6 (commit)
       via  83ab7accf4cb82f8acd995c551d94f3faef6ab2d (commit)
       via  b918f63f3ee64ff9f5a60afcdb6be14656969e8d (commit)
       via  a92e5930ffbcb178a2d2420ee2f6d4834ffa90e1 (commit)
       via  fcc61ea37437fbfd163c5a96a7119bbcf69073e1 (commit)
       via  15598b57901bc6abcd6b49337445a4c8fe31e15a (commit)
       via  e6539c51b325451425d1c603309ce7a3aa271cf1 (commit)
       via  1b4e0d11d36bcb78fa1ad275ad24c444d99fab3d (commit)
       via  182b85b9ec9d1e52c4e3e203aab0df52321f69df (commit)
       via  df62a917da68d83533cfd9031c2048f4080846f0 (commit)
       via  429a30caa73d80a363a47f307c8688c073d15145 (commit)
       via  91966b562ed11a933df764db54b56a893fce09b9 (commit)
       via  8b43b732bc02e027da01ca715437d8ec06027524 (commit)
       via  1502b08925c227152c3064b221af7a5659ac00cc (commit)
       via  ea0f541309cc7d3251c62cf02841bd8fcb2c2571 (commit)
       via  2d70714a64fb9429a28227597cbb9beadbe8e578 (commit)
       via  63d7247a9cace6cc729441508c0cfd82f043ff4d (commit)
       via  4ae69da5ea4eb2791af6a09edc6dfaedada6d325 (commit)
       via  ee6e6eec050a38d9e795df86fa7a45ca313f8845 (commit)
       via  a5355ec55721b6d874168d979338044c4a12dc52 (commit)
       via  c1e864656dc757b0ed255b6ec33ef00c9c7d2070 (commit)
       via  a2769ec68bd81a33096a981d7299bd1b3804882c (commit)
       via  977452b2ba22fbeeea982480569822be62a4151c (commit)
       via  ba9769bc8c22c49fe1be6536d4684661ea2e079b (commit)
       via  8dc7ec2cb48d74a6fd808f6989ec08771f4bb98f (commit)
       via  4a618b7040022b9f1b18d030139f09ddabc4e3e3 (commit)
       via  b66775dc53f4117868e66d829d7fc37572865235 (commit)
       via  9751a107057cfe19e16e778e945d76b456d3b434 (commit)
       via  e8df19f3d2f4ac68da498b6c114cc08f7a452bfd (commit)
       via  87b80b667f77d38bfd24bf4ae49cad10e0f1c9d1 (commit)
       via  e2957762ba13f55aea8c7d964362a932466f5a35 (commit)
       via  35dacc36716bdac66bc2673a6725083dc265d310 (commit)
       via  12ff7a47f4426bc44103f0123d44fc111608ae18 (commit)
       via  5a312946c5a61fbc7ba1d6223769ebc05e143c64 (commit)
       via  8a13f530ea2c76e0ae7c9a4bc125ccf44395e5d2 (commit)
       via  ca345e9b995323e443c7c341942166f7675cddc4 (commit)
       via  161271070e5b242a2bf885d76805990ec11148ea (commit)
       via  af75070bee41816cb9ee4a53995d1f42870c1fcb (commit)
       via  7f7ff937453dc70144d1b6226fb7b34368ab271d (commit)
       via  ce0fe06349753b2ad1cfa7b0b1cfcaa77c4e47ab (commit)
       via  447c0fc2715ef690f47bda0da60ee3c3d750950d (commit)
       via  bec089e7aa1e2befcedb31a842d18de31bca4206 (commit)
       via  2f94771f419423d25b4dc4bc6927c49add0ad196 (commit)
       via  d78c9ccd1003f7ea933819c84d05ca0332f4afaf (commit)
       via  0088273dba9fb6cfde673f2a951320a5055e7075 (commit)
       via  7ee2573f17a78e305e5d2cbe510d577732fc497e (commit)
       via  f571aebbdbee36256e3c243e555887996e4b7dff (commit)
       via  90d2c8c2127a91634722cf243cd492998a4c9148 (commit)
       via  bb08964f2726a168b77dfe147bbec1b737215aa9 (commit)
       via  c204e5ff0cbdb71eb8fe05c31252dc1d0674d300 (commit)
       via  60e8f11850f338aef0742578f1e97f0db9c0548a (commit)
       via  9f00abec0388ccbce07b67d5e2490e3e6c383456 (commit)
       via  0c45ed935d81d7df958604ae4df34fda7181fca8 (commit)
       via  7d60132816341e15a853f2f66f06d0755d0f2daa (commit)
      from  fe2a80fe109e0e8dc60957ded5a93b39f429e1f1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=d83b3bf6465b49f2e171038aebd822cd2d67698b
commit d83b3bf6465b49f2e171038aebd822cd2d67698b
Author: Chris Young <chris at unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris at unsatisfactorysoftware.co.uk>

    Get the icon direct from the node

diff --git a/desktop/tree.c b/desktop/tree.c
index 2e35b5b..93d6a63 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -1556,9 +1556,9 @@ const char *tree_node_element_get_text(struct node_element *element)
  *
  * \return  the node element's icon
  */
-struct bitmap *tree_node_element_get_icon(struct node_element *element)
+struct bitmap *tree_node_get_icon(struct node *node)
 {
-	return element->bitmap;
+	return node->data.bitmap;
 }
 
 
diff --git a/desktop/tree.h b/desktop/tree.h
index 20ade30..87b0216 100644
--- a/desktop/tree.h
+++ b/desktop/tree.h
@@ -200,7 +200,7 @@ void tree_update_node_element(struct tree *tree, struct node_element *element,
 		const char *text, void *bitmap);
 bool tree_update_element_text(struct tree *tree, struct node_element *element, char *text);
 const char *tree_node_element_get_text(struct node_element *element);
-struct bitmap *tree_node_element_get_icon(struct node_element *element);
+struct bitmap *tree_node_get_icon(struct node *node);
 struct node *tree_get_root(struct tree *tree);
 bool tree_is_edited(struct tree *tree);
 tree_drag_type tree_drag_status(struct tree *tree);
diff --git a/desktop/tree_url_node.c b/desktop/tree_url_node.c
index 8472fff..099be81 100644
--- a/desktop/tree_url_node.c
+++ b/desktop/tree_url_node.c
@@ -342,11 +342,7 @@ const char *tree_url_node_get_url(struct node *node)
 
 struct bitmap *tree_url_node_get_icon(struct node *node)
 {
-	struct node_element *element;
-	element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
-	if (element == NULL)
-		return NULL;
-	return tree_node_element_get_icon(element);
+	return tree_node_get_icon(node);
 }
 
 


commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=96e8990faf6927663198c27bb075e03370681c8f
commit 96e8990faf6927663198c27bb075e03370681c8f
Author: Chris Young <chris at unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris at unsatisfactorysoftware.co.uk>

    Temporarily disable BitMap free for debugging

diff --git a/amiga/bitmap.c b/amiga/bitmap.c
index 9a71d1c..b1abb16 100644
--- a/amiga/bitmap.c
+++ b/amiga/bitmap.c
@@ -383,7 +383,7 @@ static struct BitMap *ami_bitmap_get_truecolour(struct bitmap *bitmap,int width,
 		}
 		else
 		{
-			if(bitmap->nativebm) p96FreeBitMap(bitmap->nativebm);
+/* TODO: fix this			if(bitmap->nativebm) p96FreeBitMap(bitmap->nativebm); */
 			bitmap->nativebm = NULL;
 		}
 	}


commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=fde868b81c687eb48cd44aff1b81184008729a82
commit fde868b81c687eb48cd44aff1b81184008729a82
Author: Chris Young <chris at unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris at unsatisfactorysoftware.co.uk>

    Revert revert in this branch

diff --git a/amiga/menu.c b/amiga/menu.c
index bcf42af..bfe5f17 100644
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -159,6 +159,33 @@ static void ami_menu_alloc_item(struct gui_window_2 *gwin, int num, UBYTE type,
 		}
 	}
 
+	if((GadToolsBase->lib_Version > 53) ||
+		((GadToolsBase->lib_Version == 53) && (GadToolsBase->lib_Revision >= 5))) {
+		/* GadTools 53.5+ only. For now we will only create the menu
+			using label.image if there's a bitmap associated with the item. */
+		if(bm != NULL) {
+			struct DrawInfo *dri = GetScreenDrawInfo(scrn);
+			struct BitMap *menu_icon = ami_bitmap_get_native(bm, 16, 16, NULL);
+
+			if(menu_icon) {
+				gwin->menuobj[num] = LabelObject,
+					LABEL_DrawInfo, dri,
+					LABEL_DisposeImage, TRUE,
+					LABEL_Image, BitMapObject,
+						BITMAP_Screen, scrn,
+						BITMAP_BitMap, menu_icon,
+						BITMAP_Width, 16,
+						BITMAP_Height, 16,
+					BitMapEnd,
+					LABEL_Text, gwin->menulab[num],
+				LabelEnd;
+
+				gwin->menutype[num] |= MENU_IMAGE;
+			}
+			FreeScreenDrawInfo(scrn, dri);
+		}
+	}
+
 	if(key) gwin->menukey[num] = key;
 	if(func) gwin->menu_hook[num].h_Entry = (HOOKFUNC)func;
 	if(hookdata) gwin->menu_hook[num].h_Data = hookdata;


-----------------------------------------------------------------------

Summary of changes:
 !NetSurf/Resources/CSS,f79          |    1 +
 !NetSurf/Resources/internal.css,f79 |   27 +-
 .gitignore                          |    1 +
 Docs/BUILDING-GTK                   |    8 +-
 amiga/Makefile.target               |   10 +-
 amiga/arexx.c                       |    6 +-
 amiga/bitmap.c                      |    4 +-
 amiga/clipboard.c                   |    6 +-
 amiga/context_menu.c                |    4 +-
 amiga/dist/Install                  |    2 +-
 amiga/download.c                    |    6 +-
 amiga/drag.c                        |    6 +-
 amiga/file.c                        |    8 +-
 amiga/font.c                        |   15 +-
 amiga/font_scan.c                   |    2 +-
 amiga/gui.c                         |  218 +++++--
 amiga/gui_options.c                 |   53 +-
 amiga/launch.c                      |    2 +-
 amiga/menu.c                        |   35 +-
 amiga/options.h                     |  264 ++-----
 amiga/plotters.c                    |   20 +-
 amiga/print.c                       |    2 +-
 amiga/stringview/urlhistory.c       |    2 +-
 amiga/system_colour.c               |  367 ----------
 amiga/theme.c                       |    4 +-
 amiga/thumbnail.c                   |    2 +-
 amiga/tree.c                        |    4 +-
 atari/Makefile.target               |    1 -
 atari/bitmap.c                      |    2 +-
 atari/ctxmenu.c                     |    2 +-
 atari/deskmenu.c                    |    4 +-
 atari/download.c                    |    2 +-
 atari/font.c                        |    2 +-
 atari/gui.c                         |   81 ++-
 atari/history.c                     |    2 +-
 atari/hotlist.c                     |    2 +-
 atari/misc.c                        |    2 +-
 atari/options.h                     |   90 +--
 atari/plot/font_freetype.c          |   22 +-
 atari/plot/plot.c                   |    2 +-
 atari/settings.c                    |   10 +-
 atari/system_colour.c               |  288 --------
 atari/toolbar.c                     |    2 +-
 beos/Makefile.target                |    2 +-
 beos/fetch_rsrc.cpp                 |    2 +-
 beos/font.cpp                       |    2 +-
 beos/gui.cpp                        |  156 ++++-
 beos/gui_options.cpp                |    2 +-
 beos/options.h                      |   17 +-
 beos/plotters.cpp                   |    2 +-
 beos/scaffolding.cpp                |    2 +-
 beos/system_colour.cpp              |  387 ----------
 beos/window.cpp                     |    2 +-
 cocoa/BrowserView.m                 |    2 +-
 cocoa/BrowserViewController.m       |    2 +-
 cocoa/BrowserWindowController.m     |    2 +-
 cocoa/Makefile.target               |    1 -
 cocoa/NetSurfAppDelegate.m          |    2 +-
 cocoa/NetsurfApp.m                  |   32 +-
 cocoa/PreferencesWindowController.m |    2 +-
 cocoa/font.m                        |    2 +-
 cocoa/gui.m                         |    2 +-
 cocoa/system_colour.m               |  282 --------
 content/content.c                   |    7 +-
 content/content.h                   |    6 +
 content/fetch.c                     |    2 +-
 content/fetchers/about.c            |   11 +-
 content/fetchers/curl.c             |   10 +-
 content/fetchers/data.c             |    2 +-
 content/fetchers/file.c             |    2 +-
 content/fetchers/resource.c         |    2 +-
 content/hlcache.c                   |   11 +
 content/llcache.c                   |   15 +-
 content/llcache.h                   |    6 +
 content/urldb.c                     |   43 ++-
 css/select.c                        |    2 +-
 css/utils.c                         |    2 +-
 css/utils.h                         |   27 +-
 desktop/Makefile                    |    4 +-
 desktop/browser.c                   |   24 +-
 desktop/cookies.c                   |    2 +-
 desktop/download.c                  |    3 +
 desktop/gui.h                       |    4 -
 desktop/netsurf.c                   |   33 +-
 desktop/netsurf.h                   |    2 +-
 desktop/options.c                   |  475 ------------
 desktop/options.h                   |  375 ++++++----
 desktop/options_main.h              |  401 -----------
 desktop/print.c                     |    2 +-
 desktop/save_pdf/font_haru.c        |    2 +-
 desktop/save_pdf/pdf_plotters.c     |    2 +-
 desktop/scrollbar.c                 |    2 +-
 desktop/search.c                    |    2 +-
 desktop/searchweb.c                 |    2 +-
 desktop/system_colour.c             |  101 +++
 desktop/thumbnail.c                 |    2 +-
 desktop/tree.c                      |    6 +-
 desktop/tree.h                      |    2 +-
 desktop/tree_url_node.c             |    8 +-
 framebuffer/Makefile.target         |    2 +-
 framebuffer/font_freetype.c         |    2 +-
 framebuffer/font_internal.c         |    2 +-
 framebuffer/gui.c                   |  141 +++--
 framebuffer/localhistory.c          |    2 +-
 framebuffer/options.h               |  122 ++---
 framebuffer/system_colour.c         |  282 --------
 gtk/Makefile.target                 |    2 +-
 gtk/bitmap.c                        |   52 ++-
 gtk/completion.c                    |    2 +-
 gtk/dialogs/preferences.c           |   22 +-
 gtk/dialogs/source.c                |    2 +-
 gtk/download.c                      |    2 +-
 gtk/font_pango.c                    |    4 +-
 gtk/gui.c                           |   96 ++-
 gtk/hotlist.c                       |    2 +-
 gtk/options.h                       |  114 ++--
 gtk/plotters.c                      |    2 +-
 gtk/print.c                         |    2 +-
 gtk/res/options.gtk3.ui             |   32 +-
 gtk/scaffolding.c                   |    6 +-
 gtk/system_colour.c                 |  282 --------
 gtk/tabs.c                          |    2 +-
 gtk/theme.c                         |    2 +-
 gtk/window.c                        |    8 +-
 image/gif.c                         |    2 +-
 image/mng.c                         |    2 +-
 javascript/Makefile                 |    2 +-
 javascript/WebIDL/console.idl       |    4 +
 javascript/js.h                     |   10 +-
 javascript/jsapi.c                  |  309 ++++++++-
 javascript/jsapi.h                  |   31 +-
 javascript/jsapi/htmldocument.bnd   |    1 +
 javascript/jsapi/navigator.bnd      |    2 +-
 javascript/jsapi/window.bnd         |  271 +++++---
 javascript/none.c                   |    4 +-
 monkey/Makefile.target              |    2 +-
 monkey/font.c                       |    2 +-
 monkey/main.c                       |   58 ++-
 monkey/options.h                    |   76 +--
 monkey/system_colour.c              |  282 --------
 render/box.c                        |    2 +-
 render/box_construct.c              |    2 +-
 render/font.c                       |    2 +-
 render/html.c                       | 1347 ++++++++++++++++-------------------
 render/html_css.c                   |    7 +-
 render/html_interaction.c           |    2 +-
 render/html_internal.h              |    6 +
 render/html_object.c                |    3 +-
 render/html_redraw.c                |    6 +-
 render/html_script.c                |   14 +-
 render/layout.c                     |    2 +-
 render/textplain.c                  |    2 +-
 resources/FatMessages               |    6 +-
 riscos/Makefile.target              |    2 +-
 riscos/bitmap.c                     |    2 +-
 riscos/buffer.c                     |    4 +-
 riscos/configure/con_cache.c        |    2 +-
 riscos/configure/con_connect.c      |    2 +-
 riscos/configure/con_content.c      |    6 +-
 riscos/configure/con_fonts.c        |    2 +-
 riscos/configure/con_home.c         |    2 +-
 riscos/configure/con_image.c        |   10 +-
 riscos/configure/con_inter.c        |    2 +-
 riscos/configure/con_language.c     |    2 +-
 riscos/configure/con_memory.c       |    2 +-
 riscos/configure/con_secure.c       |    2 +-
 riscos/configure/con_theme.c        |    2 +-
 riscos/cookies.c                    |    2 +-
 riscos/dialog.c                     |    4 +-
 riscos/download.c                   |    2 +-
 riscos/font.c                       |    2 +-
 riscos/global_history.c             |    2 +-
 riscos/gui.c                        |  176 ++++--
 riscos/help.c                       |    2 +-
 riscos/history.c                    |    2 +-
 riscos/hotlist.c                    |    2 +-
 riscos/iconbar.c                    |    2 +-
 riscos/image.c                      |    6 +-
 riscos/menus.c                      |    2 +-
 riscos/options.h                    |  165 ++----
 riscos/print.c                      |    2 +-
 riscos/save.c                       |    2 +-
 riscos/system_colour.c              |  354 ---------
 riscos/system_colour.h              |   34 -
 riscos/theme.c                      |    2 +-
 riscos/theme_install.c              |    2 +-
 riscos/thumbnail.c                  |    2 +-
 riscos/toolbar.c                    |    2 +-
 riscos/url_complete.c               |    2 +-
 riscos/window.c                     |    6 +-
 test/Makefile                       |   10 +-
 test/data/Choices                   |  104 +++
 test/js/core.infinite.html          |   23 +
 test/js/core.recursion.html         |   21 +
 test/js/index.html                  |    6 +
 test/nsoption.c                     |   86 +++
 test/urldbtest.c                    |    2 +-
 utils/Makefile                      |    4 +-
 utils/bloom.c                       |  163 +++++
 utils/bloom.h                       |   99 +++
 utils/fetch-transifex.pl            |    3 +
 utils/log.c                         |   24 +-
 utils/memdebug.c                    |  381 ----------
 utils/memdebug.h                    |  106 ---
 utils/nsoption.c                    |  896 +++++++++++++++++++++++
 utils/nsoption.h                    |  343 +++++++++
 windows/Makefile.target             |    2 +-
 windows/font.c                      |    2 +-
 windows/gui.c                       |    4 +-
 windows/main.c                      |   40 +-
 windows/prefs.c                     |    9 +-
 windows/system_colour.c             |  282 --------
 212 files changed, 4776 insertions(+), 6397 deletions(-)
 delete mode 100644 amiga/system_colour.c
 delete mode 100644 atari/system_colour.c
 delete mode 100644 beos/system_colour.cpp
 delete mode 100644 cocoa/system_colour.m
 delete mode 100644 desktop/options.c
 delete mode 100644 desktop/options_main.h
 create mode 100644 desktop/system_colour.c
 delete mode 100644 framebuffer/system_colour.c
 delete mode 100644 gtk/system_colour.c
 delete mode 100644 monkey/system_colour.c
 delete mode 100644 riscos/system_colour.c
 delete mode 100644 riscos/system_colour.h
 create mode 100644 test/data/Choices
 create mode 100644 test/js/core.infinite.html
 create mode 100644 test/js/core.recursion.html
 create mode 100644 test/nsoption.c
 create mode 100644 utils/bloom.c
 create mode 100644 utils/bloom.h
 delete mode 100644 utils/memdebug.c
 delete mode 100644 utils/memdebug.h
 create mode 100644 utils/nsoption.c
 create mode 100644 utils/nsoption.h
 delete mode 100644 windows/system_colour.c

diff --git a/!NetSurf/Resources/CSS,f79 b/!NetSurf/Resources/CSS,f79
index a7396ac..0ac6738 100644
--- a/!NetSurf/Resources/CSS,f79
+++ b/!NetSurf/Resources/CSS,f79
@@ -90,6 +90,7 @@ th { font-weight: bold; text-align: center; }
 td[nowrap], th[nowrap] { white-space: nowrap; }
 
 a:link { color: #00f; text-decoration: underline; }
+a:visited { color: #609; }
 
 img { color: #888; }
 
diff --git a/!NetSurf/Resources/internal.css,f79 b/!NetSurf/Resources/internal.css,f79
index 819c19f..96ea65f 100644
--- a/!NetSurf/Resources/internal.css,f79
+++ b/!NetSurf/Resources/internal.css,f79
@@ -164,15 +164,34 @@ body#dirlist span.size + span.size {
  * configuration listing style 
  */
 
-body#configlist table.config th {
-	text-align: left; }
+body#configlist table.config {
+	border-spacing: 0; }
+
+body#configlist table.config tr:nth-child(2n-1) {
+	background: #eee; }
 
-body#configlist table.config td {
+body#configlist table.config tr:first-child th {
+	text-align: left;
+	font-weight: bold;
+	font-family: sans-serif;
+	background: #ddd; }
+
+body#configlist table.config tr th {
+	text-align: left;
+	font-weight: normal;
+	font-family: monospace; }
+
+body#configlist table.config td, body#configlist table.config th {
 	padding-left: 1em; }
 
-body#configlist table.config td + td {
+body#configlist table.config tr *:nth-child(3) {
 	padding-left: 3em; }
 
+body#configlist table.config tr *:nth-child(4) {
+	padding-left: 3em;
+	font-family: monospace;
+	padding-right: 1em; }
+
 body#configlist .null-content {
         font-style: italic; }
 
diff --git a/.gitignore b/.gitignore
index 84eca23..82d6b6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ windows/res/preferences
 \!NetSurf/Resources/nl/Templates,fec
 \!NetSurf/Resources/nl/Messages
 \!NetSurf/Resources/it/Messages
+test/nsoption
 test/nsurl
 test/urldbtest
 test/llcache
diff --git a/Docs/BUILDING-GTK b/Docs/BUILDING-GTK
index 01f4632..16b15a4 100644
--- a/Docs/BUILDING-GTK
+++ b/Docs/BUILDING-GTK
@@ -66,9 +66,11 @@
 
   Debian-like OS:
 
-      $ apt-get install libglade2-dev libcurl3-dev libmng-dev 
+      $ apt-get install libgtk2.0-dev libcurl3-dev libmng-dev 
       $ apt-get install librsvg2-dev liblcms1-dev libjpeg-dev
 
+  If you want to build with gtk 3 replace libgtk2.0-dev with libgtk-3-dev 
+
   Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
   note that when it has not been built with OpenSSL, the SSL_CTX is not
   available and results that certification details won't be presented in case
@@ -82,8 +84,8 @@
 
   Fedora:
 
-      $ yum install libglade2-devel curl-devel libmng-devel
-      $ yum install librsvg2-devel lcms-devel
+      $ yum install curl-devel libmng-devel
+      $ yum install librsvg2-devel lcms-devel expat-devel
 
   Other:
 
diff --git a/amiga/Makefile.target b/amiga/Makefile.target
index b51a1fa..33ce41e 100644
--- a/amiga/Makefile.target
+++ b/amiga/Makefile.target
@@ -72,14 +72,14 @@ EXETARGET := NetSurf
 # ----------------------------------------------------------------------------
 
 # S_AMIGA are sources purely for the Amiga build
-S_AMIGA := gui.c tree.c history.c hotlist.c schedule.c file.c	\
+S_AMIGA := gui.c tree.c history.c hotlist.c schedule.c file.c		\
 	thumbnail.c misc.c bitmap.c font.c filetype.c utf8.c login.c	\
 	plotters.c object.c menu.c save_pdf.c arexx.c version.c		\
-	cookies.c context_menu.c clipboard.c help.c	font_scan.c			\
-	launch.c search.c history_local.c download.c iff_dr2d.c 	\
-	sslcert.c gui_options.c print.c	theme.c	drag.c icon.c system_colour.c \
+	cookies.c context_menu.c clipboard.c help.c font_scan.c	\
+	launch.c search.c history_local.c download.c iff_dr2d.c		\
+	sslcert.c gui_options.c print.c	theme.c	drag.c icon.c  		\
 	datatypes.c dt_picture.c dt_anim.c dt_sound.c plugin_hack.c	\
-	stringview/stringview.c stringview/urlhistory.c				\
+	stringview/stringview.c stringview/urlhistory.c			\
 	agclass/amigaguide_class.c
 S_AMIGA := $(addprefix amiga/,$(S_AMIGA))
 
diff --git a/amiga/arexx.c b/amiga/arexx.c
index 491fc03..ed05f6c 100644
--- a/amiga/arexx.c
+++ b/amiga/arexx.c
@@ -23,7 +23,7 @@
 #include "amiga/gui.h"
 #include "amiga/hotlist.h"
 #include "amiga/theme.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 #include "desktop/browser_private.h"
 
@@ -455,13 +455,13 @@ STATIC VOID rx_pubscreen(struct ARexxCmd *cmd, struct RexxMsg *rxm __attribute__
 {
 	cmd->ac_RC = 0;
 
-	if(nsoption_charp(use_pubscreen) == NULL)
+	if(nsoption_charp(pubscreen_name) == NULL)
 	{
 		strcpy(result,"NetSurf");
 	}
 	else
 	{
-		strcpy(result, nsoption_charp(use_pubscreen));
+		strcpy(result, nsoption_charp(pubscreen_name));
 	}
 
 	cmd->ac_Result = result;
diff --git a/amiga/bitmap.c b/amiga/bitmap.c
index c70212a..b1abb16 100644
--- a/amiga/bitmap.c
+++ b/amiga/bitmap.c
@@ -28,7 +28,7 @@
 #include <graphics/composite.h>
 #endif
 #include <graphics/gfxbase.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include <proto/datatypes.h>
 #include <datatypes/pictureclass.h>
 #include <proto/dos.h>
@@ -383,7 +383,7 @@ static struct BitMap *ami_bitmap_get_truecolour(struct bitmap *bitmap,int width,
 		}
 		else
 		{
-			if(bitmap->nativebm) p96FreeBitMap(bitmap->nativebm);
+/* TODO: fix this			if(bitmap->nativebm) p96FreeBitMap(bitmap->nativebm); */
 			bitmap->nativebm = NULL;
 		}
 	}
diff --git a/amiga/clipboard.c b/amiga/clipboard.c
index 2a4f2ab..fd42f4d 100644
--- a/amiga/clipboard.c
+++ b/amiga/clipboard.c
@@ -19,7 +19,7 @@
 #include "desktop/gui.h"
 #include "desktop/plotters.h"
 #include "desktop/textinput.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 #include "amiga/bitmap.h"
 #include "amiga/clipboard.h"
@@ -238,7 +238,7 @@ void gui_set_clipboard(const char *buffer, size_t length,
 	{
 		if(!(PushChunk(iffh, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)))
 		{
-			if(nsoption_bool(utf8_clipboard))
+			if(nsoption_bool(clipboard_write_utf8))
 			{
 				if(!(PushChunk(iffh, 0, ID_CSET, 32)))
 				{
@@ -254,7 +254,7 @@ void gui_set_clipboard(const char *buffer, size_t length,
 		}
 
 		if(!(PushChunk(iffh, 0, ID_CHRS, IFFSIZE_UNKNOWN))) {
-			if(nsoption_bool(utf8_clipboard)) {
+			if(nsoption_bool(clipboard_write_utf8)) {
 				WriteChunkBytes(iffh, buffer, length);
 			} else {
 				if(utf8_to_local_encoding(buffer, length, &text) == UTF8_CONVERT_OK) {
diff --git a/amiga/context_menu.c b/amiga/context_menu.c
index c6c9be8..839b603 100644
--- a/amiga/context_menu.c
+++ b/amiga/context_menu.c
@@ -34,7 +34,7 @@
 #include "amiga/gui.h"
 #include "amiga/history_local.h"
 #include "amiga/iff_dr2d.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/plugin_hack.h"
 #include "amiga/theme.h"
 #include "amiga/tree.h"
@@ -728,6 +728,8 @@ static uint32 ami_context_menu_hook(struct Hook *hook,Object *item,APTR reserved
 		{
 			case CMID_SELECTFILE:
 				if(AslRequestTags(filereq,
+					ASLFR_Window, gwin->win,
+					ASLFR_SleepWindow, TRUE,
 					ASLFR_TitleText,messages_get("NetSurf"),
 					ASLFR_Screen,scrn,
 					ASLFR_DoSaveMode,FALSE,
diff --git a/amiga/dist/Install b/amiga/dist/Install
index c2eabb7..3977629 100755
--- a/amiga/dist/Install
+++ b/amiga/dist/Install
@@ -558,7 +558,7 @@
 			(help @textfile-help)
 			(dest #user-options)
 			(append "theme:" #theme "\n")
-			(append "use_pubscreen:Workbench\n")
+			(append "pubscreen_name:Workbench\n")
 		)
 
 		(if (= #hotlist-exist 0)
diff --git a/amiga/download.c b/amiga/download.c
index e461c5f..6b0e3c8 100644
--- a/amiga/download.c
+++ b/amiga/download.c
@@ -34,7 +34,7 @@
 #include "amiga/download.h"
 #include "amiga/icon.h"
 #include "amiga/object.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/bitmap.h"
 #include "amiga/iff_dr2d.h"
 #include "amiga/file.h"
@@ -105,6 +105,8 @@ struct gui_download_window *gui_download_window_create(download_context *ctx,
 	else
 	{
 		if(AslRequestTags(savereq,
+			ASLFR_Window, gui->shared->win,
+			ASLFR_SleepWindow, TRUE,
 			ASLFR_TitleText,messages_get("NetSurf"),
 			ASLFR_Screen,scrn,
 			ASLFR_InitialFile, download_context_get_filename(ctx),
@@ -351,6 +353,8 @@ gui_window_save_link(struct gui_window *g, const char *url, const char *title)
 	linkname = ASPrintf("Link_to_%s",FilePart(url));
 
 	if(AslRequestTags(savereq,
+		ASLFR_Window, g->shared->win,
+		ASLFR_SleepWindow, TRUE,
 		ASLFR_TitleText,messages_get("NetSurf"),
 		ASLFR_Screen,scrn,
 		ASLFR_InitialFile,linkname,
diff --git a/amiga/drag.c b/amiga/drag.c
index c8b4416..1123ba2 100644
--- a/amiga/drag.c
+++ b/amiga/drag.c
@@ -37,7 +37,7 @@
 #include "amiga/drag.h"
 #include "amiga/file.h"
 #include "amiga/filetype.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/theme.h"
 
 #include "utils/errors.h"
@@ -55,7 +55,7 @@ void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
 {
 	const char *filetype = NULL;
 
-	if(strcmp(nsoption_charp(use_pubscreen), "Workbench")) return;
+	if(strcmp(nsoption_charp(pubscreen_name), "Workbench")) return;
 
 	switch(type)
 	{
@@ -106,7 +106,7 @@ void ami_drag_save(struct Window *win)
 	ami_drag_icon_close(NULL);
 	ami_autoscroll = FALSE;
 
-	if(nsoption_charp(use_pubscreen) && (strcmp(nsoption_charp(use_pubscreen),"Workbench") == 0))
+	if(nsoption_charp(pubscreen_name) && (strcmp(nsoption_charp(pubscreen_name),"Workbench") == 0))
 	{
 		which = WhichWorkbenchObject(NULL,scrn->MouseX,scrn->MouseY,
 									WBOBJA_Type,&type,
diff --git a/amiga/file.c b/amiga/file.c
index 49c0afe..6942857 100644
--- a/amiga/file.c
+++ b/amiga/file.c
@@ -29,7 +29,7 @@
 #include "content/fetch.h"
 
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/save_pdf/pdf_plotters.h"
 #include "desktop/save_text.h"
@@ -83,6 +83,8 @@ void ami_file_open(struct gui_window_2 *gwin)
 
 	if(AslRequestTags(filereq,
 			ASLFR_TitleText, messages_get("NetSurf"),
+			ASLFR_Window, gwin->win,
+			ASLFR_SleepWindow, TRUE,
 			ASLFR_Screen, scrn,
 			ASLFR_DoSaveMode, FALSE,
 			ASLFR_RejectIcons, TRUE,
@@ -213,7 +215,7 @@ void ami_file_save(int type, char *fname, struct Window *win,
 						FWrite(fh, source_data, 1, strlen(source_data));
 						FClose(fh);
 					}
-					free(source_data);
+					free((void *)source_data);
 				}
 			break;
 		}
@@ -229,6 +231,8 @@ void ami_file_save_req(int type, struct gui_window_2 *gwin,
 	char *fname = AllocVec(1024, MEMF_CLEAR | MEMF_PRIVATE);
 
 	if(AslRequestTags(savereq,
+			ASLFR_Window, gwin->win,
+			ASLFR_SleepWindow, TRUE,
 			ASLFR_TitleText, messages_get("NetSurf"),
 			ASLFR_Screen, scrn,
 			ASLFR_InitialFile, object ? FilePart(nsurl_access(hlcache_handle_get_url(object))) : "",
diff --git a/amiga/font.c b/amiga/font.c
index 5ec5203..21f2635 100755
--- a/amiga/font.c
+++ b/amiga/font.c
@@ -23,7 +23,7 @@
 #include "amiga/gui.h"
 #include "amiga/utf8.h"
 #include "amiga/object.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "css/css.h"
 #include "css/utils.h"
 #include "render/font.h"
@@ -327,6 +327,8 @@ bool nsfont_split(const plot_font_style_t *fstyle,
 						utf16next, emwidth);
 		}
 
+		tx += tempx;
+
 		/* Check whether we have a space */
 		if (*(string + utf8_pos) == ' ') {
 			/* Got a space */
@@ -347,11 +349,10 @@ bool nsfont_split(const plot_font_style_t *fstyle,
 			free(outf16);
 			return true;
 		}
-		
-		tx += tempx;
+
 		utf16 = utf16next;
 		utf8_pos = utf8_next(string, length, utf8_pos);
-	}
+	};
 
 	free(outf16);
 
@@ -881,10 +882,10 @@ void ami_font_setdevicedpi(int id)
 {
 	DisplayInfoHandle dih;
 	struct DisplayInfo dinfo;
-	ULONG ydpi = nsoption_int(amiga_ydpi);
-	ULONG xdpi = nsoption_int(amiga_ydpi);
+	ULONG ydpi = nsoption_int(screen_ydpi);
+	ULONG xdpi = nsoption_int(screen_ydpi);
 
-	nscss_screen_dpi = INTTOFIX(nsoption_int(amiga_ydpi));
+	nscss_screen_dpi = INTTOFIX(nsoption_int(screen_ydpi));
 
 	if(id && (nsoption_int(monitor_aspect_x) != 0) && (nsoption_int(monitor_aspect_y) != 0))
 	{
diff --git a/amiga/font_scan.c b/amiga/font_scan.c
index 768fcee..b1732da 100644
--- a/amiga/font_scan.c
+++ b/amiga/font_scan.c
@@ -45,7 +45,7 @@
 #include "amiga/object.h"
 #include "amiga/utf8.h"
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 
diff --git a/amiga/gui.c b/amiga/gui.c
index 97e45e5..a5cac9d 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -23,7 +23,7 @@
 #include "desktop/history_core.h"
 #include "desktop/mouse.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/scrollbar.h"
 #include "desktop/searchweb.h"
@@ -102,6 +102,8 @@
 #include <intuition/icclass.h>
 #include <graphics/rpattr.h>
 #include <workbench/workbench.h>
+#include <intuition/gui.h>
+#include <intuition/screens.h>
 
 /* ReAction libraries */
 #include <proto/bevel.h>
@@ -131,6 +133,8 @@
 #include <math.h>
 #include <string.h>
 
+#define AMINS_SCROLLERPEN NUMDRIPENS
+
 #define NSA_KBD_SCROLL_PX 10
 
 /* Extra mouse button defines to match those in intuition/intuition.h */
@@ -192,6 +196,12 @@ static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw);
 static void ami_do_redraw(struct gui_window_2 *g);
 static void ami_schedule_redraw_remove(struct gui_window_2 *gwin);
 
+/* accessors for default options - user option is updated if it is set as per default */
+#define nsoption_default_set_int(OPTION, VALUE)				\
+	if (nsoptions_default[NSOPTION_##OPTION].value.i == nsoptions[NSOPTION_##OPTION].value.i)	\
+		nsoptions[NSOPTION_##OPTION].value.i = VALUE;	\
+	nsoptions_default[NSOPTION_##OPTION].value.i = VALUE
+
 STRPTR ami_locale_langs(void)
 {
 	struct Locale *locale;
@@ -281,6 +291,8 @@ bool ami_gui_check_resource(char *fullpath, const char *file)
 	ami_gui_map_filename(&remapped, fullpath, file, "Resource.map");
 	path_add_part(fullpath, 1024, remapped);
 
+	LOG(("Checking for %s", fullpath));
+	
 	if(lock = Lock(fullpath, ACCESS_READ))
 	{
 		UnLock(lock);
@@ -307,9 +319,6 @@ bool ami_locate_resource(char *fullpath, const char *file)
 	found = ami_gui_check_resource(fullpath, file);
 	if(found) return true;
 
-	/* Secondly check the user's selected theme.  NB: ami_locate_resource()
-	 * gets called for Messages before options are loaded */
-
 	if(nsoption_charp(theme))
 	{
 		strcpy(fullpath, nsoption_charp(theme));
@@ -391,7 +400,108 @@ void ami_open_resources(void)
 	//ami_help_init(NULL);
 }
 
-void ami_set_options(void)
+static UWORD ami_system_colour_scrollbar_fgpen(struct DrawInfo *drinfo)
+{
+	LONG scrollerfillpen = FALSE;
+
+	GetGUIAttrs(NULL, drinfo, GUIA_PropKnobColor, &scrollerfillpen, TAG_DONE);
+
+	if(scrollerfillpen) return FILLPEN;
+		else return FOREGROUNDPEN;
+}
+
+/**
+ * set option from pen
+ */
+static nserror
+colour_option_from_pen(UWORD pen,
+			   enum nsoption_e option,
+			   struct Screen *screen,
+			   colour def_colour)
+{
+	ULONG colour[3];
+	struct DrawInfo *drinfo;
+
+	if((option < NSOPTION_SYS_COLOUR_START) ||
+	   (option > NSOPTION_SYS_COLOUR_END) ||
+	   (nsoptions[option].type != OPTION_COLOUR)) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	if(screen != NULL) {
+		drinfo = GetScreenDrawInfo(screen);
+		if(drinfo != NULL) {
+
+			if(pen == AMINS_SCROLLERPEN) pen = ami_system_colour_scrollbar_fgpen(drinfo);
+
+			/* Get the colour of the pen being used for "pen" */
+			GetRGB32(screen->ViewPort.ColorMap, drinfo->dri_Pens[pen], 1, (ULONG *)&colour);
+
+			/* convert it to a color */
+			def_colour = ((colour[0] & 0xff000000) >> 24) |
+				((colour[1] & 0xff000000) >> 16) |
+				((colour[2] & 0xff000000) >> 8);
+
+			FreeScreenDrawInfo(screen, drinfo);
+		}
+	}
+
+	if (nsoptions_default[option].value.c == nsoptions[option].value.c)
+		nsoptions[option].value.c = def_colour;
+	nsoptions_default[option].value.c = def_colour;
+
+	return NSERROR_OK;
+}
+
+static void ami_set_screen_defaults(struct Screen *screen)
+{
+	nsoption_default_set_int(window_x, 0);
+	nsoption_default_set_int(window_y, screen->BarHeight + 1);
+	nsoption_default_set_int(window_width, screen->Width);
+	nsoption_default_set_int(window_height, screen->Height - screen->BarHeight - 1);
+
+	nsoption_default_set_int(redraw_tile_size_x, screen->Width);
+	nsoption_default_set_int(redraw_tile_size_y, screen->Height);
+
+	/* set system colours for amiga ui */
+	colour_option_from_pen(FILLPEN, NSOPTION_sys_colour_ActiveBorder, screen, 0x00000000);
+	colour_option_from_pen(FILLPEN, NSOPTION_sys_colour_ActiveCaption, screen, 0x00dddddd);
+	colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_AppWorkspace, screen, 0x00eeeeee);
+	colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_Background, screen, 0x00aa0000);
+	colour_option_from_pen(FOREGROUNDPEN, NSOPTION_sys_colour_ButtonFace, screen, 0x00aaaaaa);
+	colour_option_from_pen(FORESHINEPEN, NSOPTION_sys_colour_ButtonHighlight, screen, 0x00cccccc);
+	colour_option_from_pen(FORESHADOWPEN, NSOPTION_sys_colour_ButtonShadow, screen, 0x00bbbbbb);
+	colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_ButtonText, screen, 0x00000000);
+	colour_option_from_pen(FILLTEXTPEN, NSOPTION_sys_colour_CaptionText, screen, 0x00000000);
+	colour_option_from_pen(DISABLEDTEXTPEN, NSOPTION_sys_colour_GrayText, screen, 0x00777777);
+	colour_option_from_pen(SELECTPEN, NSOPTION_sys_colour_Highlight, screen, 0x00ee0000);
+	colour_option_from_pen(SELECTTEXTPEN, NSOPTION_sys_colour_HighlightText, screen, 0x00000000);
+	colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_InactiveBorder, screen, 0x00000000);
+	colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_InactiveCaption, screen, 0x00ffffff);
+	colour_option_from_pen(INACTIVEFILLTEXTPEN, NSOPTION_sys_colour_InactiveCaptionText, screen, 0x00cccccc);
+	colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_InfoBackground, screen, 0x00aaaaaa);/* This is wrong, HelpHint backgrounds are pale yellow but doesn't seem to be a DrawInfo pen defined for it. */
+	colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_InfoText, screen, 0x00000000);
+	colour_option_from_pen(MENUBACKGROUNDPEN, NSOPTION_sys_colour_Menu, screen, 0x00aaaaaa);
+	colour_option_from_pen(MENUTEXTPEN, NSOPTION_sys_colour_MenuText, screen, 0x00000000);
+	colour_option_from_pen(AMINS_SCROLLERPEN, NSOPTION_sys_colour_Scrollbar, screen, 0x00aaaaaa);
+	colour_option_from_pen(FORESHADOWPEN, NSOPTION_sys_colour_ThreeDDarkShadow, screen, 0x00555555);
+	colour_option_from_pen(FOREGROUNDPEN, NSOPTION_sys_colour_ThreeDFace, screen, 0x00dddddd);
+	colour_option_from_pen(FORESHINEPEN, NSOPTION_sys_colour_ThreeDHighlight, screen, 0x00aaaaaa);
+	colour_option_from_pen(HALFSHINEPEN, NSOPTION_sys_colour_ThreeDLightShadow, screen, 0x00999999);
+	colour_option_from_pen(HALFSHADOWPEN, NSOPTION_sys_colour_ThreeDShadow, screen, 0x00777777);
+	colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_Window, screen, 0x00aaaaaa);
+	colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_WindowFrame, screen, 0x00000000);
+	colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_WindowText, screen, 0x00000000);
+}
+
+
+/**
+ * Set option defaults for amiga frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror ami_set_options(struct nsoption_s *defaults)
 {
 	STRPTR tempacceptlangs;
 	BPTR lock = 0;
@@ -440,9 +550,6 @@ void ami_set_options(void)
 			       (char *)strdup("PROGDIR:Resources/ca-bundle"));
 
 	
-	nsoption_setnull_charp(search_engines_file,
-			(char *)strdup("PROGDIR:Resources/SearchEngines"));
-
 	search_engines_file_location = nsoption_charp(search_engines_file);
 
 	sprintf(temp, "%s/FontGlyphCache", current_user_dir);
@@ -474,24 +581,16 @@ void ami_set_options(void)
 		}
 	}
 
-	nsoption_setnull_charp(theme,
-			(char *)strdup("PROGDIR:Resources/Themes/Default"));
-
 	tree_set_icon_dir(strdup("ENV:Sys"));
 
-	nsoption_setnull_charp(arexx_dir, (char *)strdup("Rexx"));
-	nsoption_setnull_charp(arexx_startup, (char *)strdup("Startup.nsrx"));
-	nsoption_setnull_charp(arexx_shutdown, (char *)strdup("Shutdown.nsrx"));
-
-	if(!nsoption_int(window_width)) nsoption_set_int(window_width, 800);
-	if(!nsoption_int(window_height)) nsoption_set_int(window_height, 600);
-	
 #ifndef __amigaos4__
 	nsoption_set_bool(download_notify, false);
 	nsoption_set_bool(context_menu, false);
 	nsoption_set_bool(font_antialiasing, false);
 	nsoption_set_bool(truecolour_mouse_pointers, false);
 #endif
+
+	return NSERROR_OK;
 }
 
 void ami_amiupdate(void)
@@ -553,13 +652,6 @@ nsurl *gui_get_resource_url(const char *path)
 	return url;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
-{
-	/* Set defaults for absent option strings */
-	ami_set_options(); /* check options and set defaults where required */
-}
-
 void gui_init(int argc, char** argv)
 {
 	BPTR lock = 0;
@@ -591,8 +683,7 @@ void gui_init(int argc, char** argv)
 
 static void ami_gui_newprefs_hook(struct Hook *hook, APTR window, APTR reserved)
 {
-	gui_system_colour_finalize();
-	gui_system_colour_init();
+	ami_set_screen_defaults(scrn);
 }
 
 void ami_openscreen(void)
@@ -604,12 +695,12 @@ void ami_openscreen(void)
 		compositing = ~0UL;
 	else compositing = nsoption_int(screen_compositing);
 
-	if (nsoption_charp(use_pubscreen) == NULL)
+	if (nsoption_charp(pubscreen_name) == NULL)
 	{
-		if((nsoption_charp(modeid)) && 
-		   (strncmp(nsoption_charp(modeid), "0x", 2) == 0))
+		if((nsoption_charp(screen_modeid)) && 
+		   (strncmp(nsoption_charp(screen_modeid), "0x", 2) == 0))
 		{
-			id = strtoul(nsoption_charp(modeid), NULL, 0);
+			id = strtoul(nsoption_charp(screen_modeid), NULL, 0);
 		}
 		else
 		{
@@ -625,8 +716,8 @@ void ami_openscreen(void)
 					char *modeid = malloc(20);
 					id = screenmodereq->sm_DisplayID;
 					sprintf(modeid, "0x%lx", id);
-					nsoption_set_charp(modeid, modeid);
-					nsoption_write(current_user_options);
+					nsoption_set_charp(screen_modeid, modeid);
+					nsoption_write(current_user_options, NULL, NULL);
 				}
 				FreeAslRequest(screenmodereq);
 			}
@@ -653,15 +744,15 @@ void ami_openscreen(void)
 			}
 			else
 			{
-				nsoption_set_charp(use_pubscreen,
+				nsoption_set_charp(pubscreen_name,
 						   strdup("Workbench"));
 			}
 		}
 	}
 
-	if (nsoption_charp(use_pubscreen) != NULL)
+	if (nsoption_charp(pubscreen_name) != NULL)
 	{
-		scrn = LockPubScreen(nsoption_charp(use_pubscreen));
+		scrn = LockPubScreen(nsoption_charp(pubscreen_name));
 
 		if(scrn == NULL)
 		{
@@ -672,8 +763,7 @@ void ami_openscreen(void)
 	dri = GetScreenDrawInfo(scrn);
 	ami_font_setdevicedpi(id);
 
-	gui_system_colour_finalize();
-	gui_system_colour_init();
+	ami_set_screen_defaults(scrn);
 	
 	//ami_help_new_screen(scrn);
 }
@@ -687,6 +777,7 @@ void ami_openscreenfirst(void)
 
 static void gui_init2(int argc, char** argv)
 {
+	struct Screen *screen;
 	nsurl *url;
 	nserror error;
 	struct browser_window *bw = NULL;
@@ -706,6 +797,16 @@ static void gui_init2(int argc, char** argv)
 
 	/* Treeview init code ends up calling a font function which needs this */
 	glob = &browserglob;
+
+	/* ...and this ensures the treeview at least gets the WB colour palette to work with */
+	if(scrn == NULL) {
+		if(screen = LockPubScreen("Workbench")) {
+			ami_set_screen_defaults(screen);
+			UnlockPubScreen(NULL, screen);
+		}
+	} else {
+		ami_set_screen_defaults(scrn);
+	}
 	/**/
 
 	ami_hotlist_initialise(nsoption_charp(hotlist_file));
@@ -816,7 +917,7 @@ static void gui_init2(int argc, char** argv)
 		}
 	}
 
-    	nsoption_setnull_charp(homepage_url, (char *)strdup(NETSURF_HOMEPAGE));
+	nsoption_setnull_charp(homepage_url, (char *)strdup(NETSURF_HOMEPAGE));
 
 	if(!notalreadyrunning)
 	{
@@ -832,7 +933,6 @@ static void gui_init2(int argc, char** argv)
 			sendcmd = ASPrintf("OPEN \"%s\" NEW",nsoption_charp(homepage_url));
 		}
 		IDoMethod(arexx_obj,AM_EXECUTE,sendcmd,"NETSURF",NULL,NULL,NULL,NULL);
-		IDoMethod(arexx_obj,AM_EXECUTE,"TOFRONT","NETSURF",NULL,NULL,NULL,NULL);
 		FreeVec(sendcmd);
 
 		netsurf_quit=true;
@@ -905,7 +1005,7 @@ int main(int argc, char** argv)
 	char temp[1024];
 	BPTR lock = 0;
 	int32 user = 0;
-	
+	nserror ret;
 	Object *splash_window = ami_gui_splash_open();
 
 	user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY);
@@ -917,9 +1017,6 @@ int main(int argc, char** argv)
 
 	current_user_options = ASPrintf("%s/Choices", current_user_dir);
 
-	if(ami_locate_resource(messages, "Messages") == false)
-		die("Cannot open Messages file");
-
 	ami_mime_init("PROGDIR:Resources/mimetypes");
 	sprintf(temp, "%s/mimetypes.user", current_user_dir);
 	ami_mime_init(temp);
@@ -929,7 +1026,26 @@ int main(int argc, char** argv)
 	amiga_plugin_hack_init();
 	amiga_datatypes_init();
 
-	netsurf_init(&argc, &argv, current_user_options, messages);
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(NULL, &argc, argv);
+
+	/* user options setup */
+	ret = nsoption_init(ami_set_options, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	nsoption_read(current_user_options, NULL);
+	nsoption_commandline(&argc, argv, NULL);
+
+	if(ami_locate_resource(messages, "Messages") == false)
+		die("Cannot open Messages file");
+	
+	ret = netsurf_init(messages);
+	if (ret != NSERROR_OK) {
+		die("NetSurf failed to initialise");
+	}
 
 	amiga_icon_init();
 
@@ -3118,7 +3234,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
 							CLICKTAB_Labels, &g->shared->tab_list,
 							TAG_DONE);
 
-		if(nsoption_bool(new_tab_active))
+		if(nsoption_bool(new_tab_is_active))
 		{
 			RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS],g->shared->win,NULL,
 							CLICKTAB_Current,g->tab,
@@ -3131,7 +3247,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
 		g->shared->tabs++;
 		g->shared->next_tab++;
 
-		if(nsoption_bool(new_tab_active)) ami_switch_tab(g->shared,false);
+		if(nsoption_bool(new_tab_is_active)) ami_switch_tab(g->shared,false);
 
 		ami_update_buttons(g->shared);
 
@@ -3174,9 +3290,9 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
 		ULONG addtabclosegadget = TAG_IGNORE;
 		ULONG iconifygadget = FALSE;
 
-		if (nsoption_charp(use_pubscreen) && 
+		if (nsoption_charp(pubscreen_name) && 
 		    (locked_screen == TRUE) &&
-		    (strcmp(nsoption_charp(use_pubscreen), "Workbench") == 0))
+		    (strcmp(nsoption_charp(pubscreen_name), "Workbench") == 0))
 				iconifygadget = TRUE;
 		ami_create_menu(g->shared);
 
@@ -3629,6 +3745,8 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
 	if(locked_screen) UnlockPubScreen(NULL,scrn);
 	search_web_retrieve_ico(false);
 
+	ScreenToFront(scrn);
+
 	return g;
 }
 
@@ -3668,7 +3786,7 @@ ULONG ami_get_border_gadget_balance(struct gui_window_2 *gwin, ULONG *size1, ULO
 
 	available_width = gwin->win->Width - scrn->WBorLeft - sz;
 
-	gad1percent = nsoption_int(toolbar_status_width) / 10000.0;
+	gad1percent = nsoption_int(toolbar_status_size) / 10000.0;
 
 	*size1 = (ULONG)(available_width * gad1percent);
 	*size2 = (ULONG)(available_width * (1 - gad1percent));
diff --git a/amiga/gui_options.c b/amiga/gui_options.c
index 96ac2e4..e436cd2 100755
--- a/amiga/gui_options.c
+++ b/amiga/gui_options.c
@@ -38,7 +38,7 @@
 #include "amiga/utf8.h"
 #include "utils/messages.h"
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/searchweb.h"
 
 #include <proto/window.h>
@@ -415,9 +415,9 @@ void ami_gui_opts_open(void)
 		return;
 	}
 
-	if(nsoption_charp(use_pubscreen))
+	if(nsoption_charp(pubscreen_name))
 	{
-		if(strcmp(nsoption_charp(use_pubscreen),"Workbench") == 0)
+		if(strcmp(nsoption_charp(pubscreen_name),"Workbench") == 0)
 		{
 			screenoptsselected = 1;
 			screennamedisabled = TRUE;
@@ -435,9 +435,10 @@ void ami_gui_opts_open(void)
 		screennamedisabled = TRUE;
 	}
 
-	if((nsoption_charp(modeid)) && (strncmp(nsoption_charp(modeid),"0x",2) == 0))
+	if((nsoption_charp(screen_modeid)) && 
+	   (strncmp(nsoption_charp(screen_modeid),"0x",2) == 0))
 	{
-		screenmodeid = strtoul(nsoption_charp(modeid),NULL,0);
+		screenmodeid = strtoul(nsoption_charp(screen_modeid),NULL,0);
 	}
 
 	if(nsoption_bool(http_proxy))
@@ -579,7 +580,7 @@ void ami_gui_opts_open(void)
       	              						GA_ID, GID_OPTS_HIDEADS,
          	           						GA_RelVerify, TRUE,
          	           						GA_Text, gadlab[GID_OPTS_HIDEADS],
-         	           						GA_Selected, nsoption_bool(block_ads),
+         	           						GA_Selected, nsoption_bool(block_advertisements),
             	    					CheckBoxEnd,
 									LayoutEnd, // content blocking
 									LAYOUT_AddChild,VGroupObject,
@@ -693,7 +694,7 @@ void ami_gui_opts_open(void)
 												GA_ID, GID_OPTS_SCREENNAME,
 												GA_RelVerify, TRUE,
 												GA_Disabled,screennamedisabled,
-												STRINGA_TextVal, nsoption_bool(use_pubscreen),
+												STRINGA_TextVal, nsoption_charp(pubscreen_name),
 												STRINGA_BufferPos,0,
 											StringEnd,
 										LayoutEnd,
@@ -743,7 +744,7 @@ void ami_gui_opts_open(void)
       	              					GA_ID, GID_OPTS_PTROS,
          	           					GA_RelVerify, TRUE,
          	           					GA_Text, gadlab[GID_OPTS_PTROS],
-         	           					GA_Selected, nsoption_bool(use_os_pointers),
+         	           					GA_Selected, nsoption_bool(os_mouse_pointers),
             	    				CheckBoxEnd,
 								LayoutEnd, // mouse
 								CHILD_WeightedHeight,0,
@@ -942,7 +943,7 @@ void ami_gui_opts_open(void)
 										LAYOUT_AddChild, gow->objects[GID_OPTS_DPI_Y] = IntegerObject,
 											GA_ID, GID_OPTS_DPI_Y,
 											GA_RelVerify, TRUE,
-											INTEGER_Number, nsoption_int(amiga_ydpi),
+											INTEGER_Number, nsoption_int(screen_ydpi),
 											INTEGER_Minimum, 60,
 											INTEGER_Maximum, 150,
 											INTEGER_Arrows, TRUE,
@@ -1163,7 +1164,7 @@ void ami_gui_opts_open(void)
       	              						GA_ID, GID_OPTS_TAB_ACTIVE,
          	        	   					GA_RelVerify, TRUE,
          	     	      					GA_Text, gadlab[GID_OPTS_TAB_ACTIVE],
-         	     	      					GA_Selected, !nsoption_bool(new_tab_active),
+         	     	      					GA_Selected, !nsoption_bool(new_tab_is_active),
             	    					CheckBoxEnd,
 										LAYOUT_AddChild, gow->objects[GID_OPTS_TAB_LAST] = CheckBoxObject,
       	              						GA_ID, GID_OPTS_TAB_LAST,
@@ -1274,7 +1275,7 @@ void ami_gui_opts_open(void)
       		              					GA_ID, GID_OPTS_CLIPBOARD,
          		           					GA_RelVerify, TRUE,
          	    	       					GA_Text, gadlab[GID_OPTS_CLIPBOARD],
-         	    	       					GA_Selected, nsoption_bool(utf8_clipboard),
+         	    	       					GA_Selected, nsoption_bool(clipboard_write_utf8),
             	    					CheckBoxEnd,
 									LayoutEnd, // clipboard
 									CHILD_WeightedHeight, 0,
@@ -1531,9 +1532,9 @@ void ami_gui_opts_use(bool save)
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_HIDEADS],(ULONG *)&data);
 	if (data) {
-		nsoption_set_bool(block_ads, true);
+		nsoption_set_bool(block_advertisements, true);
 	} else {
-		nsoption_set_bool(block_ads, false);
+		nsoption_set_bool(block_advertisements, false);
 	}
 
 	GetAttr(INTEGER_Number,gow->objects[GID_OPTS_HISTORY],(ULONG *)&nsoption_int(expire_url));
@@ -1572,16 +1573,16 @@ void ami_gui_opts_use(bool save)
 	switch(data)
 	{
 		case 0:
-			nsoption_set_charp(use_pubscreen, strdup("\0"));
+			nsoption_set_charp(pubscreen_name, strdup("\0"));
 			break;
 
 		case 1:
-			nsoption_set_charp(use_pubscreen, (char *)strdup("Workbench"));
+			nsoption_set_charp(pubscreen_name, (char *)strdup("Workbench"));
 			break;
 
 		case 2:
 			GetAttr(STRINGA_TextVal,gow->objects[GID_OPTS_SCREENNAME],(ULONG *)&data);
-			nsoption_set_charp(use_pubscreen, (char *)strdup((char *)data));
+			nsoption_set_charp(pubscreen_name, (char *)strdup((char *)data));
 			break;
 	}
 
@@ -1590,7 +1591,7 @@ void ami_gui_opts_use(bool save)
 	{
 		char *modeid = malloc(20);
 		sprintf(modeid,"0x%lx", id);
-		nsoption_set_charp(modeid, modeid);
+		nsoption_set_charp(screen_modeid, modeid);
 	}
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_WIN_SIMPLE],(ULONG *)&data);
@@ -1614,9 +1615,9 @@ void ami_gui_opts_use(bool save)
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_PTROS],(ULONG *)&data);
 	if (data) {
-		nsoption_set_bool(use_os_pointers, true);
+		nsoption_set_bool(os_mouse_pointers, true);
 	} else {
-		nsoption_set_bool(use_os_pointers, false);
+		nsoption_set_bool(os_mouse_pointers, false);
 	}
 
 	GetAttr(CHOOSER_Selected,gow->objects[GID_OPTS_PROXY],(ULONG *)&data);
@@ -1667,7 +1668,7 @@ void ami_gui_opts_use(bool save)
 		nsoption_set_bool(animate_images, true);
 	}
 
-	GetAttr(INTEGER_Number,gow->objects[GID_OPTS_DPI_Y],(ULONG *)&nsoption_int(amiga_ydpi));
+	GetAttr(INTEGER_Number,gow->objects[GID_OPTS_DPI_Y],(ULONG *)&nsoption_int(screen_ydpi));
 	ami_font_setdevicedpi(id); // id set above
 
 	GetAttr(GETFONT_TextAttr,gow->objects[GID_OPTS_FONT_SANS],(ULONG *)&data);
@@ -1740,9 +1741,9 @@ void ami_gui_opts_use(bool save)
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_TAB_ACTIVE],(ULONG *)&data);
 	if (data) {
-		nsoption_set_bool(new_tab_active, false);
+		nsoption_set_bool(new_tab_is_active, false);
 	} else {
-		nsoption_set_bool(new_tab_active, true);
+		nsoption_set_bool(new_tab_is_active, true);
 	}
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_TAB_LAST],(ULONG *)&data);
@@ -1784,9 +1785,9 @@ void ami_gui_opts_use(bool save)
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_CLIPBOARD],(ULONG *)&data);
 	if (data) {
-		nsoption_set_bool(utf8_clipboard, true);
+		nsoption_set_bool(clipboard_write_utf8, true);
 	} else {
-		nsoption_set_bool(utf8_clipboard, false);
+		nsoption_set_bool(clipboard_write_utf8, false);
 	}
 
 	GetAttr(GA_Selected,gow->objects[GID_OPTS_CONTEXTMENU],(ULONG *)&data);
@@ -1817,6 +1818,7 @@ void ami_gui_opts_use(bool save)
 		nsoption_set_bool(hide_docky_icon, true);
 	}
 
+#ifdef WITH_PDF_EXPORT
 	GetAttr(INTEGER_Number,gow->objects[GID_OPTS_MARGIN_TOP],(ULONG *)&nsoption_int(margin_top));
 
 	GetAttr(INTEGER_Number,gow->objects[GID_OPTS_MARGIN_LEFT],(ULONG *)&nsoption_int(margin_left));
@@ -1861,6 +1863,7 @@ void ami_gui_opts_use(bool save)
 	} else {
 		nsoption_set_bool(enable_PDF_password, false);
 	}
+#endif
 
 	if(rescan_fonts == true) {
 		ami_font_finiscanner();
@@ -1868,7 +1871,7 @@ void ami_gui_opts_use(bool save)
 	}
 
 	if(save == true) {
-		nsoption_write(current_user_options);
+		nsoption_write(current_user_options, NULL, NULL);
 		ami_font_savescanner(); /* just in case it has changed and been used only */
 	}
 
diff --git a/amiga/launch.c b/amiga/launch.c
index 20505f3..3236e79 100755
--- a/amiga/launch.c
+++ b/amiga/launch.c
@@ -30,7 +30,7 @@
 #include <proto/utility.h>
 #include <proto/openurl.h>
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/url.h"
 
 struct Library *OpenURLBase = NULL;
diff --git a/amiga/menu.c b/amiga/menu.c
index 0d1925b..bfe5f17 100644
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -50,7 +50,7 @@
 #include "amiga/history_local.h"
 #include "amiga/hotlist.h"
 #include "amiga/menu.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/print.h"
 #include "amiga/search.h"
 #include "amiga/theme.h"
@@ -167,20 +167,21 @@ static void ami_menu_alloc_item(struct gui_window_2 *gwin, int num, UBYTE type,
 			struct DrawInfo *dri = GetScreenDrawInfo(scrn);
 			struct BitMap *menu_icon = ami_bitmap_get_native(bm, 16, 16, NULL);
 
-			gwin->menuobj[num] = LabelObject,
-				LABEL_DrawInfo, dri,
-				LABEL_DisposeImage, TRUE,
-				LABEL_Image, BitMapObject,
-					BITMAP_Screen, scrn,
-					BITMAP_BitMap, menu_icon,
-					BITMAP_Width, 16,
-					BITMAP_Height, 16,
-				BitMapEnd,
-				LABEL_Text, gwin->menulab[num],
-			LabelEnd;
-
-			gwin->menutype[num] |= MENU_IMAGE;
-
+			if(menu_icon) {
+				gwin->menuobj[num] = LabelObject,
+					LABEL_DrawInfo, dri,
+					LABEL_DisposeImage, TRUE,
+					LABEL_Image, BitMapObject,
+						BITMAP_Screen, scrn,
+						BITMAP_BitMap, menu_icon,
+						BITMAP_Width, 16,
+						BITMAP_Height, 16,
+					BitMapEnd,
+					LABEL_Text, gwin->menulab[num],
+				LabelEnd;
+
+				gwin->menutype[num] |= MENU_IMAGE;
+			}
 			FreeScreenDrawInfo(scrn, dri);
 		}
 	}
@@ -966,7 +967,7 @@ static void ami_menu_item_settings_snapshot(struct Hook *hook, APTR window, stru
 
 static void ami_menu_item_settings_save(struct Hook *hook, APTR window, struct IntuiMessage *msg)
 {
-	nsoption_write(current_user_options);
+	nsoption_write(current_user_options, NULL, NULL);
 }
 
 static void ami_menu_item_arexx_execute(struct Hook *hook, APTR window, struct IntuiMessage *msg)
@@ -976,6 +977,8 @@ static void ami_menu_item_arexx_execute(struct Hook *hook, APTR window, struct I
 	GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
 
 	if(AslRequestTags(filereq,
+						ASLFR_Window, gwin->win,
+						ASLFR_SleepWindow, TRUE,
 						ASLFR_TitleText, messages_get("NetSurf"),
 						ASLFR_Screen, scrn,
 						ASLFR_DoSaveMode, FALSE,
diff --git a/amiga/options.h b/amiga/options.h
index 822a7a3..b95ddf1 100644
--- a/amiga/options.h
+++ b/amiga/options.h
@@ -16,207 +16,77 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef AMIGA_OPTIONS_H
 #define AMIGA_OPTIONS_H
 
-#define NSOPTION_EXTRA_DEFINE			\
-	char *url_file;				\
-	char *hotlist_file;			\
-	char *use_pubscreen;			\
-	char *modeid;				\
-	int screen_compositing;			\
-	int amiga_ydpi;				\
-	int cache_bitmaps;			\
-	char *theme;				\
-	bool utf8_clipboard;			\
-	bool context_menu;			\
-	bool truecolour_mouse_pointers;		\
-	bool use_os_pointers;			\
-	bool use_openurl_lib;			\
-	bool new_tab_active;			\
-	bool new_tab_last;			\
-	bool tab_close_warn;			\
-	bool tab_always_show;			\
-	bool kiosk_mode;			\
-	char *search_engines_file;		\
-	char *arexx_dir;			\
-	char *arexx_startup;			\
-	char *arexx_shutdown;			\
-	char *download_dir;			\
-	bool download_notify;			\
-	bool faster_scroll;			\
-	bool scale_quality;			\
-	int dither_quality;			\
-	int mask_alpha;				\
-	bool ask_overwrite;			\
-	int printer_unit;			\
-	int print_scale;			\
-	bool startup_no_window;			\
-	bool close_no_quit;			\
-	bool hide_docky_icon;			\
-	char *font_unicode;			\
-	char *font_unicode_file;		\
-	bool font_unicode_only;		\
-	bool font_antialiasing;		\
-	bool drag_save_icons;			\
-	int hotlist_window_xpos;		\
-	int hotlist_window_ypos;		\
-	int hotlist_window_xsize;		\
-	int hotlist_window_ysize;		\
-	int history_window_xpos;		\
-	int history_window_ypos;		\
-	int history_window_xsize;		\
-	int history_window_ysize;		\
-	int cookies_window_xpos;		\
-	int cookies_window_ypos;		\
-	int cookies_window_xsize;		\
-	int cookies_window_ysize;		\
-	int web_search_width;		\
-	int cairo_renderer;			\
-	bool direct_render;			\
-	bool window_simple_refresh;			\
-	bool resize_with_contents;			\
-	int reformat_delay;			\
-	int redraw_tile_size_x;			\
-	int redraw_tile_size_y;			\
-	int monitor_aspect_x;			\
-	int monitor_aspect_y;			\
-	bool accept_lang_locale;		\
-	int menu_refresh                        
+/* currently nothing here */
+
+#endif
 
 
-#define NSOPTION_EXTRA_DEFAULTS				\
-	.url_file = NULL,				\
-	.hotlist_file = NULL,				\
-	.use_pubscreen = NULL,				\
-	.modeid = NULL,					\
-	.screen_compositing = -1,			\
-	.amiga_ydpi = 85,				\
-	.cache_bitmaps = 0,				\
-	.theme = NULL,					\
-	.utf8_clipboard = false,			\
-	.context_menu = true,				\
-	.truecolour_mouse_pointers = false,		\
-	.use_os_pointers = true,			\
-	.use_openurl_lib = false,			\
-	.new_tab_active = false,			\
-	.new_tab_last = false,				\
-	.tab_close_warn = true,				\
-	.tab_always_show = false,				\
-	.kiosk_mode = false,				\
-	.search_engines_file = NULL,			\
-	.arexx_dir = NULL,				\
-	.arexx_startup = NULL,				\
-	.arexx_shutdown = NULL,				\
-	.download_dir = NULL,				\
-	.download_notify = false,			\
-	.faster_scroll = true,				\
-	.scale_quality = false,				\
-	.dither_quality = 1,				\
-	.mask_alpha = 50,					\
-	.ask_overwrite = true,				\
-	.printer_unit = 0,				\
-	.print_scale = 100,				\
-	.startup_no_window = false,			\
-	.close_no_quit = false,				\
-	.hide_docky_icon = false,			\
-	.font_unicode = NULL,				\
-	.font_unicode_file = NULL,				\
-	.font_unicode_only = false,				\
-	.font_antialiasing = true,				\
-	.drag_save_icons = true,			\
-	.hotlist_window_xpos = 0,			\
-	.hotlist_window_ypos = 0,			\
-	.hotlist_window_xsize = 0,			\
-	.hotlist_window_ysize = 0,			\
-	.history_window_xpos = 0,			\
-	.history_window_ypos = 0,			\
-	.history_window_xsize = 0,			\
-	.history_window_ysize = 0,			\
-	.cookies_window_xpos = 0,			\
-	.cookies_window_ypos = 0,			\
-	.cookies_window_xsize = 0,			\
-	.cookies_window_ysize = 0,			\
-	.web_search_width = 0,			\
-	.cairo_renderer = 0,				\
-	.direct_render = false,				\
-	.window_simple_refresh = false,				\
-	.resize_with_contents = false,				\
-	.reformat_delay = 0,				\
-	.redraw_tile_size_x = 0,			\
-	.redraw_tile_size_y = 0,			\
-	.monitor_aspect_x = 0,				\
-	.monitor_aspect_y = 0,				\
-	.accept_lang_locale = true,			\
-	.menu_refresh = 0 
 
-#define NSOPTION_EXTRA_TABLE \
-{ "url_file",		OPTION_STRING,	&nsoptions.url_file }, \
-{ "hotlist_file",	OPTION_STRING,	&nsoptions.hotlist_file }, \
-{ "use_pubscreen",	OPTION_STRING,	&nsoptions.use_pubscreen}, \
-{ "screen_modeid",	OPTION_STRING,	&nsoptions.modeid}, \
-{ "screen_compositing",	OPTION_INTEGER,	&nsoptions.screen_compositing}, \
-{ "screen_ydpi",		OPTION_INTEGER,	&nsoptions.amiga_ydpi}, \
-{ "cache_bitmaps",	OPTION_INTEGER,	&nsoptions.cache_bitmaps}, \
-{ "theme",		OPTION_STRING,	&nsoptions.theme}, \
-{ "clipboard_write_utf8", OPTION_BOOL,	&nsoptions.utf8_clipboard}, \
-{ "context_menu",	OPTION_BOOL,	&nsoptions.context_menu}, \
-{ "truecolour_mouse_pointers", OPTION_BOOL, &nsoptions.truecolour_mouse_pointers}, \
-{ "os_mouse_pointers",	OPTION_BOOL,	&nsoptions.use_os_pointers}, \
-{ "use_openurl_lib",	OPTION_BOOL,	&nsoptions.use_openurl_lib}, \
-{ "new_tab_is_active",	OPTION_BOOL,	&nsoptions.new_tab_active}, \
-{ "new_tab_last",	OPTION_BOOL,	&nsoptions.new_tab_last}, \
-{ "tab_close_warn",	OPTION_BOOL,	&nsoptions.tab_close_warn}, \
-{ "tab_always_show",	OPTION_BOOL,	&nsoptions.tab_always_show}, \
-{ "kiosk_mode",		OPTION_BOOL,	&nsoptions.kiosk_mode},		\
-{ "search_engines_file",OPTION_STRING,	&nsoptions.search_engines_file }, \
-{ "arexx_dir",		OPTION_STRING,	&nsoptions.arexx_dir }, \
-{ "arexx_startup",	OPTION_STRING,	&nsoptions.arexx_startup }, \
-{ "arexx_shutdown",	OPTION_STRING,	&nsoptions.arexx_shutdown }, \
-{ "download_dir",	OPTION_STRING,	&nsoptions.download_dir }, \
-{ "download_notify",	OPTION_BOOL,	&nsoptions.download_notify}, \
-{ "faster_scroll",	OPTION_BOOL,	&nsoptions.faster_scroll}, \
-{ "scale_quality",	OPTION_BOOL,	&nsoptions.scale_quality}, \
-{ "dither_quality",	OPTION_INTEGER,	&nsoptions.dither_quality}, \
-{ "mask_alpha",		OPTION_INTEGER,	&nsoptions.mask_alpha},	\
-{ "ask_overwrite",	OPTION_BOOL,	&nsoptions.ask_overwrite}, \
-{ "printer_unit",	OPTION_INTEGER,	&nsoptions.printer_unit}, \
-{ "print_scale",	OPTION_INTEGER,	&nsoptions.print_scale}, \
-{ "startup_no_window",	OPTION_BOOL,	&nsoptions.startup_no_window}, \
-{ "close_no_quit",	OPTION_BOOL,	&nsoptions.close_no_quit}, \
-{ "hide_docky_icon",	OPTION_BOOL,	&nsoptions.hide_docky_icon}, \
-{ "font_unicode",	OPTION_STRING,	&nsoptions.font_unicode }, \
-{ "font_unicode_file",	OPTION_STRING,	&nsoptions.font_unicode_file }, \
-{ "font_unicode_only",	OPTION_BOOL,	&nsoptions.font_unicode_only }, \
-{ "font_antialiasing",	OPTION_BOOL,	&nsoptions.font_antialiasing }, \
-{ "drag_save_icons",	OPTION_BOOL,	&nsoptions.drag_save_icons}, \
-{ "hotlist_window_xpos", OPTION_INTEGER, &nsoptions.hotlist_window_xpos}, \
-{ "hotlist_window_ypos", OPTION_INTEGER, &nsoptions.hotlist_window_ypos}, \
-{ "hotlist_window_xsize", OPTION_INTEGER, &nsoptions.hotlist_window_xsize}, \
-{ "hotlist_window_ysize", OPTION_INTEGER, &nsoptions.hotlist_window_ysize}, \
-{ "history_window_xpos", OPTION_INTEGER, &nsoptions.history_window_xpos}, \
-{ "history_window_ypos", OPTION_INTEGER, &nsoptions.history_window_ypos}, \
-{ "history_window_xsize", OPTION_INTEGER, &nsoptions.history_window_xsize}, \
-{ "history_window_ysize", OPTION_INTEGER, &nsoptions.history_window_ysize}, \
-{ "cookies_window_xpos", OPTION_INTEGER, &nsoptions.cookies_window_xpos}, \
-{ "cookies_window_ypos", OPTION_INTEGER, &nsoptions.cookies_window_ypos}, \
-{ "cookies_window_xsize", OPTION_INTEGER, &nsoptions.cookies_window_xsize}, \
-{ "cookies_window_ysize", OPTION_INTEGER, &nsoptions.cookies_window_ysize}, \
-{ "web_search_width", OPTION_INTEGER, &nsoptions.web_search_width}, \
-{ "cairo_renderer",	OPTION_INTEGER,	&nsoptions.cairo_renderer}, \
-{ "direct_render",	OPTION_BOOL,	&nsoptions.direct_render}, \
-{ "window_simple_refresh",	OPTION_BOOL,	&nsoptions.window_simple_refresh}, \
-{ "resize_with_contents",	OPTION_BOOL,	&nsoptions.resize_with_contents}, \
-{ "reformat_delay",	OPTION_INTEGER,	&nsoptions.reformat_delay}, \
-{ "redraw_tile_size_x",	OPTION_INTEGER,	&nsoptions.redraw_tile_size_x}, \
-{ "redraw_tile_size_y",	OPTION_INTEGER,	&nsoptions.redraw_tile_size_y}, \
-{ "monitor_aspect_x",	OPTION_INTEGER,	&nsoptions.monitor_aspect_x}, \
-{ "monitor_aspect_y",	OPTION_INTEGER,	&nsoptions.monitor_aspect_y}, \
-{ "accept_lang_locale",	OPTION_BOOL,	&nsoptions.accept_lang_locale}, \
-{ "menu_refresh",	OPTION_INTEGER,	&nsoptions.menu_refresh}
+NSOPTION_STRING(url_file, NULL)
+NSOPTION_STRING(hotlist_file, NULL)
+NSOPTION_STRING(pubscreen_name, NULL)
+NSOPTION_STRING(screen_modeid, NULL)
+NSOPTION_INTEGER(screen_compositing, -1)
+NSOPTION_INTEGER(screen_ydpi, 85)
+NSOPTION_INTEGER(cache_bitmaps, 0)
+NSOPTION_STRING(theme, "PROGDIR:Resources/Themes/Default")
+NSOPTION_BOOL(clipboard_write_utf8, false)
+NSOPTION_BOOL(context_menu, true)
+NSOPTION_BOOL(truecolour_mouse_pointers, false)
+NSOPTION_BOOL(os_mouse_pointers, true)
+NSOPTION_BOOL(use_openurl_lib, false)
+NSOPTION_BOOL(new_tab_is_active, false)
+NSOPTION_BOOL(new_tab_last, false)
+NSOPTION_BOOL(tab_close_warn, true)
+NSOPTION_BOOL(tab_always_show, false)
+NSOPTION_BOOL(kiosk_mode, false)
+NSOPTION_STRING(search_engines_file, "PROGDIR:Resources/SearchEngines")
+NSOPTION_STRING(arexx_dir, "Rexx")
+NSOPTION_STRING(arexx_startup, "Startup.nsrx")
+NSOPTION_STRING(arexx_shutdown, "Shutdown.nsrx")
+NSOPTION_STRING(download_dir, NULL)
+NSOPTION_BOOL(download_notify, true)
+NSOPTION_BOOL(faster_scroll, true)
+NSOPTION_BOOL(scale_quality, false)
+NSOPTION_INTEGER(dither_quality, 1)
+NSOPTION_INTEGER(mask_alpha, 50)
+NSOPTION_BOOL(ask_overwrite, true)
+NSOPTION_INTEGER(printer_unit, 0)
+NSOPTION_INTEGER(print_scale, 100)
+NSOPTION_BOOL(startup_no_window, false)
+NSOPTION_BOOL(close_no_quit, false)
+NSOPTION_BOOL(hide_docky_icon, false)
+NSOPTION_STRING(font_unicode, NULL)
+NSOPTION_STRING(font_unicode_file, NULL)
+NSOPTION_BOOL(font_unicode_only, false)
+NSOPTION_BOOL(font_antialiasing, true)
+NSOPTION_BOOL(drag_save_icons, true)
+NSOPTION_INTEGER(hotlist_window_xpos, 0)
+NSOPTION_INTEGER(hotlist_window_ypos, 0)
+NSOPTION_INTEGER(hotlist_window_xsize, 0)
+NSOPTION_INTEGER(hotlist_window_ysize, 0)
+NSOPTION_INTEGER(history_window_xpos, 0)
+NSOPTION_INTEGER(history_window_ypos, 0)
+NSOPTION_INTEGER(history_window_xsize, 0)
+NSOPTION_INTEGER(history_window_ysize, 0)
+NSOPTION_INTEGER(cookies_window_xpos, 0)
+NSOPTION_INTEGER(cookies_window_ypos, 0)
+NSOPTION_INTEGER(cookies_window_xsize, 0)
+NSOPTION_INTEGER(cookies_window_ysize, 0)
+NSOPTION_INTEGER(web_search_width, 0)
+NSOPTION_INTEGER(cairo_renderer, 0)
+NSOPTION_BOOL(direct_render, false)
+NSOPTION_BOOL(window_simple_refresh, false)
+NSOPTION_BOOL(resize_with_contents, false)
+NSOPTION_INTEGER(reformat_delay, 0)
+NSOPTION_INTEGER(redraw_tile_size_x, 0)
+NSOPTION_INTEGER(redraw_tile_size_y, 0)
+NSOPTION_INTEGER(monitor_aspect_x, 0)
+NSOPTION_INTEGER(monitor_aspect_y, 0)
+NSOPTION_BOOL(accept_lang_locale, true)
+NSOPTION_INTEGER(menu_refresh, 0)
+
 
-#endif
diff --git a/amiga/plotters.c b/amiga/plotters.c
index 4d29830..bf1c2bf 100755
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -22,7 +22,8 @@
 #include "amiga/gui.h"
 #include "amiga/utf8.h"
 
-#include "desktop/options.h"
+#include "css/utils.h"
+#include "utils/nsoption.h"
 #include "utils/utils.h"
 #include "utils/log.h"
 
@@ -101,17 +102,6 @@ const struct plotter_table amiplot = {
 	.option_knockout = true,
 };
 
-colour ami_abgr_to_argb(colour c) {
-	colour argb = 0x00000000;
-
-	/* NB: We force the alpha byte to be 0xff, as it is not set by the core. */
-	argb = 0xff000000 |
-		((c & 0x00ff0000) >> 16) |
-		(c & 0x0000ff00) |
-		((c & 0x000000ff) << 16);
-
-	return argb;
-}
 
 #ifdef NS_AMIGA_CAIRO
 void ami_cairo_set_colour(cairo_t *cr,colour c)
@@ -164,8 +154,6 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height)
 		palette_mapped = false;
 	}
 
-	if(nsoption_int(redraw_tile_size_x) <= 0) nsoption_set_int(redraw_tile_size_x, scrn->Width);
-	if(nsoption_int(redraw_tile_size_y) <= 0) nsoption_set_int(redraw_tile_size_y, scrn->Height);
 	if(!width) width = nsoption_int(redraw_tile_size_x);
 	if(!height) height = nsoption_int(redraw_tile_size_y);
 
@@ -295,7 +283,7 @@ static void ami_plot_setapen(ULONG colour)
 {
 	if(palette_mapped == false) {
 		SetRPAttrs(glob->rp, RPTAG_APenColor,
-			ami_abgr_to_argb(colour),
+			ns_color_to_nscss(colour),
 			TAG_DONE);
 	} else {
 		ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colour);
@@ -307,7 +295,7 @@ static void ami_plot_setopen(ULONG colour)
 {
 	if(palette_mapped == false) {
 		SetRPAttrs(glob->rp, RPTAG_OPenColor,
-			ami_abgr_to_argb(colour),
+			ns_color_to_nscss(colour),
 			TAG_DONE);
 	} else {
 		ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colour);
diff --git a/amiga/print.c b/amiga/print.c
index ec04c62..f0689f7 100644
--- a/amiga/print.c
+++ b/amiga/print.c
@@ -20,7 +20,7 @@
 #include "amiga/plotters.h"
 #include "render/font.h"
 #include "amiga/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/print.h"
 #include "utils/messages.h"
 #include "utils/utils.h"
diff --git a/amiga/stringview/urlhistory.c b/amiga/stringview/urlhistory.c
index ec56987..fa5aec4 100644
--- a/amiga/stringview/urlhistory.c
+++ b/amiga/stringview/urlhistory.c
@@ -29,7 +29,7 @@
 #include "urlhistory.h"
 
 #include "content/urldb.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 static struct List PageList;
 
diff --git a/amiga/system_colour.c b/amiga/system_colour.c
deleted file mode 100644
index c9be5ad..0000000
--- a/amiga/system_colour.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "amiga/gui.h"
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-#include "desktop/tree.h"
-
-#include <proto/graphics.h>
-#include <proto/intuition.h>
-#include <proto/Picasso96API.h>
-#include <intuition/gui.h>
-#include <intuition/screens.h>
-
-#define AMINS_SCROLLERPEN NUMDRIPENS
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	UWORD amiga_pen;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ActiveBorder), 
-		FILLPEN,
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ActiveCaption), 
-		FILLPEN,
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_colour(sys_colour_AppWorkspace), 
-		BACKGROUNDPEN,
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_colour(sys_colour_Background), 
-		BACKGROUNDPEN,
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ButtonFace), 
-		FOREGROUNDPEN,
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ButtonHighlight), 
-		FORESHINEPEN,
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_colour(sys_colour_ButtonShadow), 
-		FORESHADOWPEN,
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ButtonText), 
-		TEXTPEN,
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_CaptionText), 
-		FILLTEXTPEN,
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_GrayText), 
-		DISABLEDTEXTPEN,
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_colour(sys_colour_Highlight), 
-		SELECTPEN,
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_HighlightText), 
-		SELECTTEXTPEN,
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveBorder), 
-		INACTIVEFILLPEN,
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveCaption), 
-		INACTIVEFILLPEN,
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_InactiveCaptionText), 
-		INACTIVEFILLTEXTPEN,
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_InfoBackground), 
-		BACKGROUNDPEN, /* This is wrong, HelpHint backgrounds are pale yellow but doesn't seem to be a DrawInfo pen defined for it. */
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_InfoText), 
-		TEXTPEN,
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Menu), 
-		MENUBACKGROUNDPEN,
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_MenuText), 
-		MENUTEXTPEN,
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Scrollbar), 
-		AMINS_SCROLLERPEN,
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_colour(sys_colour_ThreeDDarkShadow), 
-		FORESHADOWPEN,
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ThreeDFace), 
-		FOREGROUNDPEN,
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ThreeDHighlight), 
-		FORESHINEPEN,
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_colour(sys_colour_ThreeDLightShadow), 
-		HALFSHINEPEN,
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_colour(sys_colour_ThreeDShadow), 
-		HALFSHADOWPEN,
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Window), 
-		BACKGROUNDPEN,
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowFrame), 
-		INACTIVEFILLPEN,
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowText), 
-		TEXTPEN,
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-css_color ami_css_colour_from_pen(struct Screen *screen, UWORD pen);
-
-UWORD ami_system_colour_scrollbar_fgpen(struct DrawInfo *drinfo)
-{
-	LONG scrollerfillpen = FALSE;
-
-	GetGUIAttrs(NULL, drinfo, GUIA_PropKnobColor, &scrollerfillpen, TAG_DONE);
-
-	if(scrollerfillpen) return FILLPEN;
-		else return FOREGROUNDPEN;
-}
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-		else if(scrn) {
-			colour_list[ccount].colour =
-				ami_css_colour_from_pen(scrn, colour_list[ccount].amiga_pen);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	tree_setup_colours();
-
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-
-	gui_system_colour_pw = NULL;
-}
-
-colour ami_css_color_to_colour(css_color c)
-{
-	return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c & 0xFF) << 16);
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = ami_css_color_to_colour(colour_list[ccount].colour);
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
-
-css_color ami_css_colour_from_pen(struct Screen *screen, UWORD pen)
-{
-	css_color css_colour = 0x00000000;
-	ULONG colour[3];
-	struct DrawInfo *drinfo = GetScreenDrawInfo(screen);
-
-	if(drinfo == NULL) return 0x00000000;
-
-	if(pen == AMINS_SCROLLERPEN) pen = ami_system_colour_scrollbar_fgpen(drinfo);
-
-	/* Get the colour of the pen being used for "pen" */
-	GetRGB32(screen->ViewPort.ColorMap, drinfo->dri_Pens[pen], 1, (ULONG *)&colour);
-
-	/* convert it to a css_color */
-	css_colour = (0xff << 24) |
-				((colour[0] & 0xff000000) >> 8) |
-				((colour[1] & 0xff000000) >> 16) |
-				((colour[2] & 0xff000000) >> 24);
-
-	FreeScreenDrawInfo(screen, drinfo);
-	return css_colour;
-}
diff --git a/amiga/theme.c b/amiga/theme.c
index fa058e0..a0755b2 100644
--- a/amiga/theme.c
+++ b/amiga/theme.c
@@ -37,7 +37,7 @@
 #include "amiga/bitmap.h"
 #include "amiga/drag.h"
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "amiga/theme.h"
 #include "desktop/searchweb.h"
 #include "utils/messages.h"
@@ -193,7 +193,7 @@ void ami_update_pointer(struct Window *win, gui_pointer_shape shape)
 {
 	if(drag_save_data) return;
 
-	if(nsoption_bool(use_os_pointers))
+	if(nsoption_bool(os_mouse_pointers))
 	{
 		switch(shape)
 		{
diff --git a/amiga/thumbnail.c b/amiga/thumbnail.c
index f1738d2..61102fe 100755
--- a/amiga/thumbnail.c
+++ b/amiga/thumbnail.c
@@ -20,7 +20,7 @@
 #include "desktop/browser.h"
 #include "amiga/gui.h"
 #include "amiga/bitmap.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "content/urldb.h"
 #include "desktop/plotters.h"
 #include "desktop/thumbnail.h"
diff --git a/amiga/tree.c b/amiga/tree.c
index 9c7b9d6..ddaf81e 100644
--- a/amiga/tree.c
+++ b/amiga/tree.c
@@ -53,7 +53,7 @@
 #include "amiga/drag.h" /* drag icon stuff */
 #include "amiga/theme.h" /* pointers */
 #include "amiga/filetype.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "content/urldb.h"
 #include "desktop/cookies.h"
 #include "desktop/history_global_core.h"
@@ -1000,6 +1000,8 @@ BOOL ami_tree_event(struct treeview_window *twin)
 							{
 								case 0: // export
 									if(AslRequestTags(savereq,
+										ASLFR_Window, twin->win,
+										ASLFR_SleepWindow, TRUE,
 										ASLFR_TitleText,messages_get("NetSurf"),
 										ASLFR_Screen,scrn,
 										ASLFR_InitialFile,"tree_export.html",
diff --git a/atari/Makefile.target b/atari/Makefile.target
index 95d675f..bff4f07 100644
--- a/atari/Makefile.target
+++ b/atari/Makefile.target
@@ -96,7 +96,6 @@ S_ATARI := \
 	toolbar.c \
 	statusbar.c \
 	osspec.c \
-	system_colour.c \
 	ctxmenu.c \
 	settings.c \
 	deskmenu.c \
diff --git a/atari/bitmap.c b/atari/bitmap.c
index 0f27be4..6d986fb 100755
--- a/atari/bitmap.c
+++ b/atari/bitmap.c
@@ -22,7 +22,7 @@
 
 
 #include "assert.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "image/bitmap.h"
 #include "atari/bitmap.h"
 #include "atari/plot/plot.h"
diff --git a/atari/ctxmenu.c b/atari/ctxmenu.c
index 1806d54..5b33fe4 100644
--- a/atari/ctxmenu.c
+++ b/atari/ctxmenu.c
@@ -42,7 +42,7 @@
 #include "atari/rootwin.h"
 #include "atari/misc.h"
 #include "atari/clipboard.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "atari/res/netsurf.rsh"
 #include "atari/ctxmenu.h"
 
diff --git a/atari/deskmenu.c b/atari/deskmenu.c
index e2b0dea..4300498 100644
--- a/atari/deskmenu.c
+++ b/atari/deskmenu.c
@@ -5,7 +5,7 @@
 #include "utils/url.h"
 #include "desktop/browser.h"
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "atari/res/netsurf.rsh"
 #include "atari/gemtk/gemtk.h"
@@ -389,7 +389,7 @@ static void __CDECL menu_savewin(short item, short title, void *data)
 		nsoption_set_int(window_height, rect.g_h);
 		nsoption_set_int(window_x, rect.g_x);
 		nsoption_set_int(window_y, rect.g_y);
-		nsoption_write((const char*)&options);
+		nsoption_write((const char*)&options, NULL, NULL);
 	}
 
 }
diff --git a/atari/download.c b/atari/download.c
index 32a6f12..407be06 100755
--- a/atari/download.c
+++ b/atari/download.c
@@ -30,7 +30,7 @@
 #include "desktop/gui.h"
 #include "desktop/history_core.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/textinput.h"
 #include "desktop/download.h"
diff --git a/atari/font.c b/atari/font.c
index dfa0efe..7640f61 100755
--- a/atari/font.c
+++ b/atari/font.c
@@ -42,7 +42,7 @@
 #include "render/font.h"
 #include "utils/utf8.h"
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/mouse.h"
 #include "desktop/plotters.h"
 
diff --git a/atari/gui.c b/atari/gui.c
index f125142..6b54274 100644
--- a/atari/gui.c
+++ b/atari/gui.c
@@ -40,7 +40,7 @@
 #include "desktop/netsurf.h"
 #include "desktop/401login.h"
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/textinput.h"
 #include "desktop/browser.h"
@@ -922,16 +922,21 @@ nsurl *gui_get_resource_url(const char *path)
     return url;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for atari frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
     /* Set defaults for absent option strings */
     nsoption_setnull_charp(cookie_file, strdup("cookies"));
     if (nsoption_charp(cookie_file) == NULL) {
-        die("Failed initialising string options");
+        LOG(("Failed initialising string options"));
+	return NSERROR_BAD_PARAMETER;
     }
-
-    nsoption_set_int(min_reflow_period, 350);
+    return NSERROR_OK;
 }
 
 static void gui_init(int argc, char** argv)
@@ -1031,12 +1036,13 @@ static void gui_init2(int argc, char** argv)
 int main(int argc, char** argv)
 {
     char messages[PATH_MAX];
-	const char *addr;
-	char * file_url = NULL;
-	struct stat stat_buf;
-	nsurl *url;
-	nserror error;
+    const char *addr;
+    char * file_url = NULL;
+    struct stat stat_buf;
+    nsurl *url;
+    nserror ret;
 
+    /* @todo logging file descriptor update belongs in a nslog_init callback */
     setbuf(stderr, NULL);
     setbuf(stdout, NULL);
 #ifdef WITH_DBG_LOGFILE
@@ -1053,8 +1059,25 @@ int main(int argc, char** argv)
     atari_find_resource((char*)&messages, "messages", "res/messages");
     atari_find_resource((char*)&options, "Choices", "Choices");
 
+    /* initialise logging - not fatal if it fails but not much we can
+     * do about it
+     */
+    nslog_init(NULL, &argc, argv);
+
+    /* user options setup */
+    ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+    if (ret != NSERROR_OK) {
+	die("Options failed to initialise");
+    }
+    nsoption_read(options, NULL);
+    nsoption_commandline(&argc, argv, NULL);
+
+    /* common initialisation */
     LOG(("Initialising core..."));
-    netsurf_init(&argc, &argv, options, messages);
+    ret = netsurf_init(messages);
+    if (ret != NSERROR_OK) {
+	die("NetSurf failed to initialise");
+    }
 
     LOG(("Initializing GUI..."));
     gui_init(argc, argv);
@@ -1073,23 +1096,23 @@ int main(int argc, char** argv)
 		}
     }
 
-	/* create an initial browser window */
-	error = nsurl_create(addr, &url);
-	if (error == NSERROR_OK) {
-		error = browser_window_create(BROWSER_WINDOW_VERIFIABLE |
-					      BROWSER_WINDOW_HISTORY,
-					      url,
-					      NULL,
-					      NULL,
-					      NULL);
-		nsurl_unref(url);
-	}
-	if (error != NSERROR_OK) {
-		warn_user(messages_get_errorcode(error), 0);
-	} else {
-		LOG(("Entering NetSurf mainloop..."));
-		netsurf_main_loop();
-	}
+    /* create an initial browser window */
+    ret = nsurl_create(addr, &url);
+    if (ret == NSERROR_OK) {
+	ret = browser_window_create(BROWSER_WINDOW_VERIFIABLE |
+				    BROWSER_WINDOW_HISTORY,
+				    url,
+				    NULL,
+				    NULL,
+				    NULL);
+	nsurl_unref(url);
+    }
+    if (ret != NSERROR_OK) {
+	warn_user(messages_get_errorcode(ret), 0);
+    } else {
+	LOG(("Entering NetSurf mainloop..."));
+	netsurf_main_loop();
+    }
 
     netsurf_exit();
 
diff --git a/atari/history.c b/atari/history.c
index aa32cbf..49e24ce 100755
--- a/atari/history.c
+++ b/atari/history.c
@@ -22,7 +22,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include "desktop/browser.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/tree.h"
 #include "desktop/tree_url_node.h"
 #include "desktop/gui.h"
diff --git a/atari/hotlist.c b/atari/hotlist.c
index adfd596..f3b093d 100755
--- a/atari/hotlist.c
+++ b/atari/hotlist.c
@@ -27,7 +27,7 @@
 #include "content/content.h"
 #include "content/hlcache.h"
 #include "content/urldb.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/hotlist.h"
 #include "desktop/tree.h"
 #include "desktop/tree_url_node.h"
diff --git a/atari/misc.c b/atari/misc.c
index e8e6a9b..96abcf5 100755
--- a/atari/misc.c
+++ b/atari/misc.c
@@ -31,7 +31,7 @@
 #include "desktop/mouse.h"
 #include "desktop/cookies.h"
 #include "desktop/tree.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/messages.h"
 #include "utils/utils.h"
 #include "utils/url.h"
diff --git a/atari/options.h b/atari/options.h
index f9bb3b4..7a4da6a 100755
--- a/atari/options.h
+++ b/atari/options.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Ole Loots <ole at monochrom.net>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -16,76 +16,32 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef NS_ATARI_OPTIONS_H_
 #define NS_ATARI_OPTIONS_H_
 
+/* setup longer default reflow time */
+#define DEFAULT_REFLOW_PERIOD 350 /* time in cs */
 
-#define NSOPTION_EXTRA_DEFINE										\
-	char *atari_font_driver;										\
-	int atari_font_monochrom;										\
-	int atari_dither;												\
-	int atari_transparency;											\
-	char *atari_face_sans_serif; /* default sans face */			\
-	char *atari_face_sans_serif_bold; /* bold sans face */			\
-	char *atari_face_sans_serif_italic; /* bold sans face */		\
-	char *atari_face_sans_serif_italic_bold; /* bold sans face */	\
-	char *atari_face_monospace; /* monospace face */				\
-	char *atari_face_monospace_bold; /* monospace face */			\
-	char *atari_face_serif; /* serif face */						\
-	char *atari_face_serif_bold; /* bold serif face */				\
-	char *atari_face_cursive;										\
-	char *atari_face_fantasy;										\
-	char *atari_editor;												\
-	char *downloads_path;											\
-	char *url_file;													\
-	char *hotlist_file;												\
-	char *tree_icons_path
-
-#define NSOPTION_EXTRA_DEFAULTS						\
-	.atari_font_driver = (char*)"freetype",			\
-	.atari_font_monochrom = 0,						\
-	.atari_dither = 1,								\
-	.atari_transparency = 1,						\
-	.atari_face_sans_serif = NULL,					\
-	.atari_face_sans_serif_bold = NULL,				\
-	.atari_face_sans_serif_italic = NULL,			\
-	.atari_face_sans_serif_italic_bold = NULL,		\
-	.atari_face_monospace = NULL,					\
-	.atari_face_monospace_bold = NULL,				\
-	.atari_face_serif = NULL,						\
-	.atari_face_serif_bold = NULL,					\
-	.atari_face_cursive = NULL,						\
-	.atari_face_fantasy = NULL,						\
-	.atari_editor = (char*)"",						\
-	.downloads_path = (char*)"downloads",			\
-	.url_file = (char*)"url.db",					\
-	.hotlist_file = (char*)"hotlist",				\
-	.tree_icons_path = (char*)"./res/icons"
+#endif
 
-#define NSOPTION_EXTRA_TABLE \
-	{ "atari_font_driver", OPTION_STRING, &nsoptions.atari_font_driver },\
-	{ "atari_font_monochrom", OPTION_INTEGER, &nsoptions.atari_font_monochrom },\
-	{ "atari_transparency", OPTION_INTEGER, &nsoptions.atari_transparency },\
-	{ "atari_dither", OPTION_INTEGER, &nsoptions.atari_dither },\
-	{ "atari_editor", OPTION_STRING, &nsoptions.atari_editor },\
-	{ "font_face_sans_serif", OPTION_STRING, &nsoptions.atari_face_sans_serif },\
-	{ "font_face_sans_serif_bold", OPTION_STRING, &nsoptions.atari_face_sans_serif_bold },\
-	{ "font_face_sans_serif_italic", OPTION_STRING, &nsoptions.atari_face_sans_serif_italic },\
-	{ "font_face_sans_serif_italic_bold", OPTION_STRING, &nsoptions.atari_face_sans_serif_italic_bold },\
-	{ "font_face_monospace", OPTION_STRING, &nsoptions.atari_face_monospace },\
-	{ "font_face_monospace_bold", OPTION_STRING, &nsoptions.atari_face_monospace_bold },\
-	{ "font_face_serif", OPTION_STRING, &nsoptions.atari_face_serif },\
-	{ "font_face_serif_bold", OPTION_STRING, &nsoptions.atari_face_serif_bold },\
-	{ "font_face_cursive", OPTION_STRING, &nsoptions.atari_face_cursive },\
-	{ "font_face_fantasy", OPTION_STRING, &nsoptions.atari_face_fantasy },\
-	{ "downloads_path", OPTION_STRING, &nsoptions.downloads_path },\
-	{ "url_file", OPTION_STRING, &nsoptions.url_file },\
-	{ "hotlist_file", OPTION_STRING, &nsoptions.hotlist_file },\
-	{ "tree_icons_path", OPTION_STRING, &nsoptions.tree_icons_path }
+NSOPTION_STRING(atari_font_driver, "freetype")
+NSOPTION_INTEGER(atari_font_monochrom, 0)
+NSOPTION_INTEGER(atari_transparency, 1)
+NSOPTION_INTEGER(atari_dither, 1)
+NSOPTION_STRING(atari_editor, NULL)
+NSOPTION_STRING(font_face_sans_serif, NULL)
+NSOPTION_STRING(font_face_sans_serif_bold, NULL)
+NSOPTION_STRING(font_face_sans_serif_italic, NULL)
+NSOPTION_STRING(font_face_sans_serif_italic_bold, NULL)
+NSOPTION_STRING(font_face_monospace, NULL)
+NSOPTION_STRING(font_face_monospace_bold, NULL)
+NSOPTION_STRING(font_face_serif, NULL)
+NSOPTION_STRING(font_face_serif_bold, NULL)
+NSOPTION_STRING(font_face_cursive, NULL)
+NSOPTION_STRING(font_face_fantasy, NULL)
+NSOPTION_STRING(downloads_path, "downloads")
+NSOPTION_STRING(url_file, "url.db")
+NSOPTION_STRING(hotlist_file, "hotlist")
+NSOPTION_STRING(tree_icons_path, "./res/icons")
 
-#endif
 
diff --git a/atari/plot/font_freetype.c b/atari/plot/font_freetype.c
index ed850bc..49e46c8 100755
--- a/atari/plot/font_freetype.c
+++ b/atari/plot/font_freetype.c
@@ -22,7 +22,7 @@
 #include <ft2build.h>
 #include FT_CACHE_H
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "atari/plot/plot.h"
 #include "atari/plot/font_freetype.h"
 #include "atari/findfile.h"
@@ -318,7 +318,7 @@ static bool ft_font_init(void)
 	/* Default font, Sans Serif */
 	font_faces[FONT_FACE_SANS_SERIF] = NULL;
 	font_faces[FONT_FACE_SANS_SERIF] = ft_new_face(
-											nsoption_charp(atari_face_sans_serif),
+											nsoption_charp(font_face_sans_serif),
                             				FONT_RESOURCE_PATH "ss.ttf",
                             				FONT_PKG_PATH FONT_FILE_SANS
 										);
@@ -331,55 +331,55 @@ static bool ft_font_init(void)
 
 	/* Sans Serif Bold*/
 	font_faces[FONT_FACE_SANS_SERIF_BOLD] =
-			ft_new_face(nsoption_charp(atari_face_sans_serif_bold),
+			ft_new_face(nsoption_charp(font_face_sans_serif_bold),
                             FONT_RESOURCE_PATH "ssb.ttf",
                             FONT_PKG_PATH FONT_FILE_SANS_BOLD);
 
 	/* Sans Serif Italic */
 	font_faces[FONT_FACE_SANS_SERIF_ITALIC] =
-			ft_new_face(nsoption_charp(atari_face_sans_serif_italic),
+			ft_new_face(nsoption_charp(font_face_sans_serif_italic),
                             FONT_RESOURCE_PATH "ssi.ttf",
                             FONT_PKG_PATH FONT_FILE_SANS_OBLIQUE);
 
 	/* Sans Serif Italic Bold */
 	font_faces[FONT_FACE_SANS_SERIF_ITALIC_BOLD] =
-			ft_new_face(nsoption_charp(atari_face_sans_serif_italic_bold),
+			ft_new_face(nsoption_charp(font_face_sans_serif_italic_bold),
                             FONT_RESOURCE_PATH "ssib.ttf",
                             FONT_PKG_PATH FONT_FILE_SANS_BOLD_OBLIQUE);
 
 	/* Monospaced */
 	font_faces[FONT_FACE_MONOSPACE] =
-			ft_new_face(nsoption_charp(atari_face_monospace),
+			ft_new_face(nsoption_charp(font_face_monospace),
                             FONT_RESOURCE_PATH "mono.ttf",
                             FONT_PKG_PATH FONT_FILE_MONO);
 
 	/* Mospaced Bold */
 	font_faces[FONT_FACE_MONOSPACE_BOLD] =
-			ft_new_face(nsoption_charp(atari_face_monospace_bold),
+			ft_new_face(nsoption_charp(font_face_monospace_bold),
                             FONT_RESOURCE_PATH "monob.ttf",
                             FONT_PKG_PATH FONT_FILE_MONO_BOLD);
 
 	/* Serif */
 	font_faces[FONT_FACE_SERIF] =
-			ft_new_face(nsoption_charp(atari_face_serif),
+			ft_new_face(nsoption_charp(font_face_serif),
                             FONT_RESOURCE_PATH "s.ttf",
                             FONT_PKG_PATH FONT_FILE_SERIF);
 
 	/* Serif Bold */
 	font_faces[FONT_FACE_SERIF_BOLD] =
-			ft_new_face(nsoption_charp(atari_face_serif_bold),
+			ft_new_face(nsoption_charp(font_face_serif_bold),
                             FONT_RESOURCE_PATH "sb.ttf",
                             FONT_PKG_PATH FONT_FILE_SERIF_BOLD);
 
 	/* Cursive */
 	font_faces[FONT_FACE_CURSIVE] =
-			ft_new_face(nsoption_charp(atari_face_cursive),
+			ft_new_face(nsoption_charp(font_face_cursive),
                             FONT_RESOURCE_PATH "cursive.ttf",
                             FONT_PKG_PATH FONT_FILE_OBLIQUE);
 
 	/* Fantasy */
 	font_faces[FONT_FACE_FANTASY] =
-			ft_new_face(nsoption_charp(atari_face_fantasy),
+			ft_new_face(nsoption_charp(font_face_fantasy),
                             FONT_RESOURCE_PATH "fantasy.ttf",
                             FONT_PKG_PATH FONT_FILE_FANTASY);
 
diff --git a/atari/plot/plot.c b/atari/plot/plot.c
index dfd9b0e..33810b7 100755
--- a/atari/plot/plot.c
+++ b/atari/plot/plot.c
@@ -34,7 +34,7 @@
 
 #include "atari/bitmap.h"
 #include "atari/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "atari/plot/plot.h"
 
 void vq_scrninfo(VdiHdl handle, short *work_out);
diff --git a/atari/settings.c b/atari/settings.c
index 5244a7f..10aceb9 100644
--- a/atari/settings.c
+++ b/atari/settings.c
@@ -9,7 +9,7 @@
 #include <stdbool.h>
 #include <cflib.h>
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plot_style.h"
 #include "atari/res/netsurf.rsh"
 #include "atari/settings.h"
@@ -113,8 +113,8 @@ static void save_settings(void)
 {
     apply_settings();
     // Save settings
-    nsoption_write( (const char*)&options );
-    nsoption_read( (const char*)&options );
+    nsoption_write( (const char*)&options, NULL, NULL);
+    nsoption_read( (const char*)&options , NULL);
     close_settings();
     form_alert(1, "[1][Some options require an netsurf restart!][OK]");
     deskmenu_update();
@@ -131,7 +131,7 @@ static void display_settings(void)
     set_text( SETTINGS_EDIT_HOMEPAGE, nsoption_charp(homepage_url),
               INPUT_HOMEPAGE_URL_MAX_LEN );
 
-    if( nsoption_bool(block_ads) ) {
+    if( nsoption_bool(block_advertisements) ) {
         OBJ_CHECK( SETTINGS_CB_HIDE_ADVERTISEMENT );
     } else {
         OBJ_UNCHECK( SETTINGS_CB_HIDE_ADVERTISEMENT );
@@ -644,7 +644,7 @@ static void apply_settings(void)
     /* "Browser" tab: */
     nsoption_set_bool(target_blank,
                       !OBJ_SELECTED(SETTINGS_CB_DISABLE_POPUP_WINDOWS));
-    nsoption_set_bool(block_ads,
+    nsoption_set_bool(block_advertisements,
                       OBJ_SELECTED(SETTINGS_CB_HIDE_ADVERTISEMENT));
     nsoption_set_charp(accept_language,
                        gemtk_obj_get_text(dlgtree, SETTINGS_BT_SEL_LOCALE));
diff --git a/atari/system_colour.c b/atari/system_colour.c
deleted file mode 100644
index 5f86733..0000000
--- a/atari/system_colour.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#define WITH_SYSTEM_COLOUR
-#ifdef WITH_SYSTEM_COLOUR
-#include <libwapcaplet/libwapcaplet.h>
-#include <libcss/libcss.h>
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-#include "desktop/plot_style.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ActiveBorder), 
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ActiveCaption), 
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_colour(sys_colour_AppWorkspace), 
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_colour(sys_colour_Background), 
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ButtonFace), 
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ButtonHighlight), 
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_colour(sys_colour_ButtonShadow), 
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ButtonText), 
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_CaptionText), 
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_GrayText), 
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_colour(sys_colour_Highlight), 
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_HighlightText), 
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveBorder), 
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveCaption), 
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_InactiveCaptionText), 
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_InfoBackground), 
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_InfoText), 
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Menu), 
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_MenuText), 
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Scrollbar), 
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_colour(sys_colour_ThreeDDarkShadow), 
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ThreeDFace), 
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ThreeDHighlight), 
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_colour(sys_colour_ThreeDLightShadow), 
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_colour(sys_colour_ThreeDShadow), 
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Window), 
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowFrame), 
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowText), 
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
-#endif
diff --git a/atari/toolbar.c b/atari/toolbar.c
index 18d8a45..79be31b 100644
--- a/atari/toolbar.c
+++ b/atari/toolbar.c
@@ -37,7 +37,7 @@
 #include "desktop/plot_style.h"
 #include "desktop/plotters.h"
 #include "desktop/tree.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/utf8.h"
 #include "atari/clipboard.h"
 #include "atari/gui.h"
diff --git a/beos/Makefile.target b/beos/Makefile.target
index 7b473dd..8df9ec3 100644
--- a/beos/Makefile.target
+++ b/beos/Makefile.target
@@ -90,7 +90,7 @@ endif
 S_BEOS := about.cpp bitmap.cpp download.cpp fetch_rsrc.cpp filetype.cpp \
 	font.cpp gui.cpp login.cpp gui_options.cpp plotters.cpp		\
 	scaffolding.cpp search.cpp schedule.cpp	thumbnail.cpp treeview.cpp \
-	throbber.cpp window.cpp system_colour.cpp
+	throbber.cpp window.cpp
 S_BEOS := $(addprefix beos/,$(S_BEOS))
 
 RDEF_BEOS := res.rdef
diff --git a/beos/fetch_rsrc.cpp b/beos/fetch_rsrc.cpp
index 6f78aaf..c52cafe 100644
--- a/beos/fetch_rsrc.cpp
+++ b/beos/fetch_rsrc.cpp
@@ -35,7 +35,7 @@ extern "C" {
 #include "content/fetch.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/url.h"
diff --git a/beos/font.cpp b/beos/font.cpp
index b73c9cc..5636743 100644
--- a/beos/font.cpp
+++ b/beos/font.cpp
@@ -35,7 +35,7 @@ extern "C" {
 #include "render/font.h"
 #include "utils/utils.h"
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 }
 
 #include "beos/gui.h"
diff --git a/beos/gui.cpp b/beos/gui.cpp
index b2f4043..7667822 100644
--- a/beos/gui.cpp
+++ b/beos/gui.cpp
@@ -53,7 +53,7 @@ extern "C" {
 #include "desktop/cookies.h"
 #include "desktop/gui.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 #include "render/form.h"
 #include "utils/filename.h"
@@ -398,11 +398,121 @@ static void gui_init2(int argc, char** argv)
 	}
 }
 
+
+#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
+/* more ui_colors, R5 only had a few defined... */
+#define B_PANEL_TEXT_COLOR ((color_which)10)
+#define B_DOCUMENT_BACKGROUND_COLOR ((color_which)11)
+#define B_DOCUMENT_TEXT_COLOR ((color_which)12)
+#define B_CONTROL_BACKGROUND_COLOR ((color_which)13)
+#define B_CONTROL_TEXT_COLOR ((color_which)14)
+#define B_CONTROL_BORDER_COLOR ((color_which)15)
+#define B_CONTROL_HIGHLIGHT_COLOR ((color_which)16)
+#define B_NAVIGATION_BASE_COLOR ((color_which)4)
+#define B_NAVIGATION_PULSE_COLOR ((color_which)17)
+#define B_SHINE_COLOR ((color_which)18)
+#define B_SHADOW_COLOR ((color_which)19)
+#define B_MENU_SELECTED_BORDER_COLOR ((color_which)9)
+#define B_TOOL_TIP_BACKGROUND_COLOR ((color_which)20)
+#define B_TOOL_TIP_TEXT_COLOR ((color_which)21)
+#define B_SUCCESS_COLOR ((color_which)100)
+#define B_FAILURE_COLOR ((color_which)101)
+#define B_MENU_SELECTED_BACKGROUND_COLOR B_MENU_SELECTION_BACKGROUND_COLOR
+#define B_RANDOM_COLOR ((color_which)0x80000000)
+#define B_MICHELANGELO_FAVORITE_COLOR ((color_which)0x80000001)
+#define B_DSANDLER_FAVORITE_SKY_COLOR ((color_which)0x80000002)
+#define B_DSANDLER_FAVORITE_INK_COLOR ((color_which)0x80000003)
+#define B_DSANDLER_FAVORITE_SHOES_COLOR ((color_which)0x80000004)
+#define B_DAVE_BROWN_FAVORITE_COLOR ((color_which)0x80000005)
+#endif
+#if defined(B_BEOS_VERSION_DANO)
+#define B_TOOL_TIP_BACKGROUND_COLOR B_TOOLTIP_BACKGROUND_COLOR
+#define B_TOOL_TIP_TEXT_COLOR B_TOOLTIP_TEXT_COLOR
+#define
+#endif
+#define NOCOL ((color_which)0)
+
+/**
+ * set option from pen
+ */
+static nserror
+set_colour_from_ui(struct nsoption_s *opts,
+                   color_which ui,
+                   enum nsoption_e option,
+                   colour def_colour)
+{
+        if (ui != NOCOL) {
+                rgb_color c;
+                if (ui == B_DESKTOP_COLOR) {
+			BScreen s;
+			c = s.DesktopColor();
+                } else {
+                        c = ui_color(ui);
+                }
+
+                def_colour = ((((uint32_t)c.blue << 16) & 0xff0000) |
+                              ((c.green << 8) & 0x00ff00) |
+                              ((c.red) & 0x0000ff));
+        }
+        return def_colour;
+}
+
+/**
+ * Set option defaults for framebuffer frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
+{
+	/* set system colours for beos ui */
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ActiveBorder, 0x00000000);
+	set_colour_from_ui(defaults, B_WINDOW_TAB_COLOR, NSOPTION_sys_colour_ActiveCaption, 0x00dddddd);
+	set_colour_from_ui(defaults, B_PANEL_BACKGROUND_COLOR, NSOPTION_sys_colour_AppWorkspace, 0x00eeeeee);
+	set_colour_from_ui(defaults, B_DESKTOP_COLOR, NSOPTION_sys_colour_Background, 0x00aa0000);
+	set_colour_from_ui(defaults, B_CONTROL_BACKGROUND_COLOR, NSOPTION_sys_colour_ButtonFace, 0x00aaaaaa);
+	set_colour_from_ui(defaults, B_CONTROL_HIGHLIGHT_COLOR, NSOPTION_sys_colour_ButtonHighlight, 0x00cccccc);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ButtonShadow, 0x00bbbbbb);
+	set_colour_from_ui(defaults, B_CONTROL_TEXT_COLOR, NSOPTION_sys_colour_ButtonText, 0x00000000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_CaptionText, 0x00000000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_GrayText, 0x00777777);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_Highlight, 0x00ee0000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_HighlightText, 0x00000000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveBorder, 0x00000000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveCaption, 0x00ffffff);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_InactiveCaptionText, 0x00cccccc);
+	set_colour_from_ui(defaults, B_TOOL_TIP_BACKGROUND_COLOR, NSOPTION_sys_colour_InfoBackground, 0x00aaaaaa);
+	set_colour_from_ui(defaults, B_TOOL_TIP_TEXT_COLOR, NSOPTION_sys_colour_InfoText, 0x00000000);
+	set_colour_from_ui(defaults, B_MENU_BACKGROUND_COLOR, NSOPTION_sys_colour_Menu, 0x00aaaaaa);
+	set_colour_from_ui(defaults, B_MENU_ITEM_TEXT_COLOR, NSOPTION_sys_colour_MenuText, 0x00000000);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_Scrollbar, 0x00aaaaaa);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDDarkShadow, 0x00555555);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDFace, 0x00dddddd);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDHighlight, 0x00aaaaaa);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDLightShadow, 0x00999999);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_ThreeDShadow, 0x00777777);
+	set_colour_from_ui(defaults, B_DOCUMENT_BACKGROUND_COLOR, NSOPTION_sys_colour_Window, 0x00aaaaaa);
+	set_colour_from_ui(defaults, NOCOL, NSOPTION_sys_colour_WindowFrame, 0x00000000);
+	set_colour_from_ui(defaults, B_DOCUMENT_TEXT_COLOR, NSOPTION_sys_colour_WindowText, 0x00000000);
+
+	return NSERROR_OK;
+}
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+        /* set log stream to be non-buffering */
+	setbuf(fptr, NULL);
+
+	return true;
+}
+
 /** Normal entry point from OS */
 int main(int argc, char** argv)
 {
-	setbuf(stderr, NULL);
-
+	nserror ret;
 	BPath options;
 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
 		options.Append("x-vnd.NetSurf");
@@ -416,11 +526,27 @@ int main(int argc, char** argv)
 
 	const char* messages = "/boot/apps/netsurf/res/en/Messages";
 
-	/* initialise netsurf */
-	netsurf_init(&argc, &argv, options.Path(), messages);
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(nslog_stream_configure, &argc, argv);
 
-    gui_init(argc, argv);
-    gui_init2(argc, argv);
+	/* user options setup */
+	ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	nsoption_read(options.Path(), NULL);
+	nsoption_commandline(&argc, argv, NULL);
+
+	/* common initialisation */
+	ret = netsurf_init(messages);
+	if (ret != NSERROR_OK) {
+		die("NetSurf failed to initialise");
+	}
+
+        gui_init(argc, argv);
+        gui_init2(argc, argv);
 
 	netsurf_main_loop();
 
@@ -432,8 +558,6 @@ int main(int argc, char** argv)
 /** called when replicated from NSBaseView::Instantiate() */
 int gui_init_replicant(int argc, char** argv)
 {
-	setbuf(stderr, NULL);
-
 	BPath options;
 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &options, true) == B_OK) {
 		options.Append("x-vnd.NetSurf");
@@ -441,6 +565,11 @@ int gui_init_replicant(int argc, char** argv)
 
 	const char* messages = "/boot/apps/netsurf/res/en/Messages";
 
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(nslog_stream_configure, &argc, argv);
+
 	/* initialise netsurf */
 	netsurf_init(&argc, &argv, options.Path(), messages);
 
@@ -450,13 +579,6 @@ int gui_init_replicant(int argc, char** argv)
 	return 0;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
-{
-	/* Set defaults for absent option strings */
-}
-
-
 void gui_init(int argc, char** argv)
 {
 	char buf[PATH_MAX];
@@ -515,7 +637,7 @@ void gui_init(int argc, char** argv)
 	find_resource(buf, "Choices", "%/Choices");
 	LOG(("Using '%s' as Preferences file", buf));
 	options_file_location = strdup(buf);
-	nsoption_read(buf);
+	nsoption_read(buf, NULL);
 
 
 	/* check what the font settings are, setting them to a default font
diff --git a/beos/gui_options.cpp b/beos/gui_options.cpp
index 62e6640..2c56cf7 100644
--- a/beos/gui_options.cpp
+++ b/beos/gui_options.cpp
@@ -23,7 +23,7 @@
 #include <string.h>
 extern "C" {
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 }
 #include "beos/gui.h"
 #include "beos/scaffolding.h"
diff --git a/beos/options.h b/beos/options.h
index 9b8a3d1..40d23a3 100644
--- a/beos/options.h
+++ b/beos/options.h
@@ -17,23 +17,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
 
 #ifndef _NETSURF_BEOS_OPTIONS_H_
 #define _NETSURF_BEOS_OPTIONS_H_
 
-#define NSOPTION_EXTRA_DEFINE			\
-	bool render_resample;			\
-	char *url_file
+/* currently nothing here */
 
-#define NSOPTION_EXTRA_DEFAULTS				\
-	.render_resample = false,			\
-	.url_file = 0
+#endif
 
-#define NSOPTION_EXTRA_TABLE \
-	{ "render_resample",	OPTION_BOOL,	&nsoptions.render_resample }, \
-	{ "url_file",		OPTION_STRING,	&nsoptions.url_file }
+NSOPTION_BOOL(render_resample, false)
+NSOPTION_STRING(url_file, NULL)
 
-#endif
diff --git a/beos/plotters.cpp b/beos/plotters.cpp
index aabf302..c2a99fe 100644
--- a/beos/plotters.cpp
+++ b/beos/plotters.cpp
@@ -35,7 +35,7 @@ extern "C" {
 #include "render/font.h"
 #include "utils/log.h"
 #include "utils/utils.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 }
 #include "beos/font.h"
 #include "beos/gui.h"
diff --git a/beos/scaffolding.cpp b/beos/scaffolding.cpp
index 9954dd6..fe40b0c 100644
--- a/beos/scaffolding.cpp
+++ b/beos/scaffolding.cpp
@@ -56,7 +56,7 @@ extern "C" {
 #include "desktop/gui.h"
 #include "desktop/netsurf.h"
 #include "desktop/plotters.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/textinput.h"
 #include "render/font.h"
 #include "render/form.h"
diff --git a/beos/system_colour.cpp b/beos/system_colour.cpp
deleted file mode 100644
index 9f3f408..0000000
--- a/beos/system_colour.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#define __STDBOOL_H__	1
-#include <assert.h>
-#include <ctype.h>
-#include <stdbool.h>
-
-#include <InterfaceDefs.h>
-#include <Screen.h>
-
-extern "C" {
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-#include "desktop/plot_style.h"
-
-}
-
-#include "beos/gui.h"
-
-
-#if !defined(__HAIKU__) && !defined(B_BEOS_VERSION_DANO)
-/* more ui_colors, R5 only had a few defined... */
-#define B_PANEL_TEXT_COLOR ((color_which)10)
-#define B_DOCUMENT_BACKGROUND_COLOR ((color_which)11)
-#define B_DOCUMENT_TEXT_COLOR ((color_which)12)
-#define B_CONTROL_BACKGROUND_COLOR ((color_which)13)
-#define B_CONTROL_TEXT_COLOR ((color_which)14)
-#define B_CONTROL_BORDER_COLOR ((color_which)15)
-#define B_CONTROL_HIGHLIGHT_COLOR ((color_which)16)
-#define B_NAVIGATION_BASE_COLOR ((color_which)4)
-#define B_NAVIGATION_PULSE_COLOR ((color_which)17)
-#define B_SHINE_COLOR ((color_which)18)
-#define B_SHADOW_COLOR ((color_which)19)
-#define B_MENU_SELECTED_BORDER_COLOR ((color_which)9)
-#define B_TOOL_TIP_BACKGROUND_COLOR ((color_which)20)
-#define B_TOOL_TIP_TEXT_COLOR ((color_which)21)
-#define B_SUCCESS_COLOR ((color_which)100)
-#define B_FAILURE_COLOR ((color_which)101)
-#define B_MENU_SELECTED_BACKGROUND_COLOR B_MENU_SELECTION_BACKGROUND_COLOR
-#define B_RANDOM_COLOR ((color_which)0x80000000)
-#define B_MICHELANGELO_FAVORITE_COLOR ((color_which)0x80000001)
-#define B_DSANDLER_FAVORITE_SKY_COLOR ((color_which)0x80000002)
-#define B_DSANDLER_FAVORITE_INK_COLOR ((color_which)0x80000003)
-#define B_DSANDLER_FAVORITE_SHOES_COLOR ((color_which)0x80000004)
-#define B_DAVE_BROWN_FAVORITE_COLOR ((color_which)0x80000005)
-#endif
-#if defined(B_BEOS_VERSION_DANO)
-#define B_TOOL_TIP_BACKGROUND_COLOR B_TOOLTIP_BACKGROUND_COLOR
-#define B_TOOL_TIP_TEXT_COLOR B_TOOLTIP_TEXT_COLOR
-#define 
-#endif
-#define NOCOL ((color_which)0)
-
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color css_colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-	color_which ui;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ActiveBorder), 
-		NULL, 
-		NOCOL
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ActiveCaption), 
-		NULL, 
-		B_WINDOW_TAB_COLOR
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_colour(sys_colour_AppWorkspace), 
-		NULL, 
-		B_PANEL_BACKGROUND_COLOR
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_colour(sys_colour_Background), 
-		NULL, 
-		B_DESKTOP_COLOR
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ButtonFace), 
-		NULL, 
-		B_CONTROL_BACKGROUND_COLOR
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ButtonHighlight), 
-		NULL, 
-		B_CONTROL_HIGHLIGHT_COLOR
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_colour(sys_colour_ButtonShadow), 
-		NULL, 
-		NOCOL
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ButtonText), 
-		NULL, 
-		B_CONTROL_TEXT_COLOR
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_CaptionText), 
-		NULL, 
-		NOCOL
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_GrayText), 
-		NULL, 
-		NOCOL
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_colour(sys_colour_Highlight), 
-		NULL, 
-		NOCOL
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_HighlightText), 
-		NULL, 
-		NOCOL
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveBorder), 
-		NULL, 
-		NOCOL
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveCaption), 
-		NULL, 
-		NOCOL
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_InactiveCaptionText), 
-		NULL, 
-		NOCOL
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_InfoBackground), 
-		NULL, 
-		B_TOOL_TIP_BACKGROUND_COLOR
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_InfoText), 
-		NULL, 
-		B_TOOL_TIP_TEXT_COLOR
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Menu), 
-		NULL, 
-		B_MENU_BACKGROUND_COLOR
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_MenuText), 
-		NULL, 
-		B_MENU_ITEM_TEXT_COLOR
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Scrollbar), 
-		NULL, 
-		NOCOL
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_colour(sys_colour_ThreeDDarkShadow), 
-		NULL, 
-		NOCOL
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ThreeDFace), 
-		NULL, 
-		NOCOL
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ThreeDHighlight), 
-		NULL, 
-		NOCOL
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_colour(sys_colour_ThreeDLightShadow), 
-		NULL, 
-		NOCOL
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_colour(sys_colour_ThreeDShadow), 
-		NULL, 
-		NOCOL
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Window), 
-		NULL, 
-		B_DOCUMENT_BACKGROUND_COLOR
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowFrame), 
-		NULL, 
-		NOCOL
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowText), 
-		NULL, 
-		B_DOCUMENT_TEXT_COLOR
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].css_colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	nsbeos_update_system_ui_colors();
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].css_colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *css_colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*css_colour = colour_list[ccount].css_colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
-
-void nsbeos_update_system_ui_colors(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (colour_list[ccount].ui == NOCOL)
-			continue;
-		rgb_color c = ui_color(colour_list[ccount].ui);
-		if (colour_list[ccount].ui == B_DESKTOP_COLOR) {
-			BScreen s;
-			c = s.DesktopColor();
-		}
-
-		//printf("uic[%d] = ui_color(%d) %02x %02x %02x %02x\n", ccount,
-		//	colour_list[ccount].ui, c.red, c.green, c.blue, c.alpha);
-
-		colour_list[ccount].css_colour = 0xff000000
-			| ((((uint32_t)c.red << 16) & 0xff0000)
-			| ((c.green << 8) & 0x00ff00)
-			| ((c.blue) & 0x0000ff));
-	}
-}
-
diff --git a/beos/window.cpp b/beos/window.cpp
index 3ce8e27..64ef616 100644
--- a/beos/window.cpp
+++ b/beos/window.cpp
@@ -25,7 +25,7 @@ extern "C" {
 #include "css/utils.h"
 #include "desktop/browser_private.h"
 #include "desktop/mouse.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/textinput.h"
 #include "render/font.h"
 #include "utils/log.h"
diff --git a/cocoa/BrowserView.m b/cocoa/BrowserView.m
index 4bda3b5..c472fd7 100644
--- a/cocoa/BrowserView.m
+++ b/cocoa/BrowserView.m
@@ -27,7 +27,7 @@
 #import "desktop/history_core.h"
 #import "desktop/plotters.h"
 #import "desktop/textinput.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "utils/messages.h"
 
 @interface BrowserView ()
diff --git a/cocoa/BrowserViewController.m b/cocoa/BrowserViewController.m
index bea383d..4952f52 100644
--- a/cocoa/BrowserViewController.m
+++ b/cocoa/BrowserViewController.m
@@ -23,7 +23,7 @@
 #import "desktop/browser_private.h"
 #import "desktop/history_core.h"
 #import "desktop/textinput.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 
 #import "utils/corestrings.h"
 #import "utils/filename.h"
diff --git a/cocoa/BrowserWindowController.m b/cocoa/BrowserWindowController.m
index 7688c1a..2edb9a1 100644
--- a/cocoa/BrowserWindowController.m
+++ b/cocoa/BrowserWindowController.m
@@ -26,7 +26,7 @@
 #import "cocoa/NetsurfApp.h"
 
 #import "desktop/browser.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "utils/messages.h"
 
 @interface BrowserWindowController ()
diff --git a/cocoa/Makefile.target b/cocoa/Makefile.target
index 7e2c198..8bd13c2 100644
--- a/cocoa/Makefile.target
+++ b/cocoa/Makefile.target
@@ -98,7 +98,6 @@ S_COCOA := \
 	url.m \
 	utf8.m \
 	utils.m \
-	system_colour.m \
 	ArrowBox.m \
 	ArrowWindow.m \
 	BlackScroller.m \
diff --git a/cocoa/NetSurfAppDelegate.m b/cocoa/NetSurfAppDelegate.m
index 0a352c6..4a66212 100644
--- a/cocoa/NetSurfAppDelegate.m
+++ b/cocoa/NetSurfAppDelegate.m
@@ -22,7 +22,7 @@
 #import "cocoa/HistoryWindowController.h"
 
 #import "desktop/browser.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "utils/messages.h"
 
 @interface NetSurfAppDelegate ()
diff --git a/cocoa/NetsurfApp.m b/cocoa/NetsurfApp.m
index 19d8437..333cbe2 100644
--- a/cocoa/NetsurfApp.m
+++ b/cocoa/NetsurfApp.m
@@ -29,7 +29,7 @@
 #import "desktop/history_core.h"
 #import "desktop/mouse.h"
 #import "desktop/netsurf.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "desktop/plotters.h"
 #import "desktop/save_complete.h"
 #import "desktop/textinput.h"
@@ -163,13 +163,20 @@ void cocoa_autorelease( void )
 	pool = [[NSAutoreleasePool alloc] init];
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for cocoa frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
 	/* Set defaults for absent option strings */
 	const char * const ca_bundle = [[[NSBundle mainBundle] pathForResource: @"ca-bundle" ofType: @""] UTF8String];
 
 	nsoption_setnull_charp(ca_bundle, strdup(ca_bundle));
+
+        return NSERROR_OK;
 }
 
 int main( int argc, char **argv )
@@ -182,7 +189,24 @@ int main( int argc, char **argv )
 	const char * const messages = [[[NSBundle mainBundle] pathForResource: @"Messages" ofType: @""] UTF8String];
 	const char * const options = cocoa_get_options_file();
 
-	netsurf_init(&argc, &argv, options, messages);
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(NULL, &argc, argv);
+
+	/* user options setup */
+	error = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (error != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	nsoption_read(options, NULL);
+	nsoption_commandline(&argc, argv, NULL);
+
+	/* common initialisation */
+	error = netsurf_init(messages);
+	if (error != NSERROR_OK) {
+		die("NetSurf failed to initialise");
+	}
 
 	/* Initialise filename allocator */
 	filename_initialise();
diff --git a/cocoa/PreferencesWindowController.m b/cocoa/PreferencesWindowController.m
index 8ee4580..a3abe29 100644
--- a/cocoa/PreferencesWindowController.m
+++ b/cocoa/PreferencesWindowController.m
@@ -24,7 +24,7 @@
 
 #import "desktop/browser_private.h"
 #import "content/content.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 
 @implementation PreferencesWindowController
 
diff --git a/cocoa/font.m b/cocoa/font.m
index 915e7c8..08fad0a 100644
--- a/cocoa/font.m
+++ b/cocoa/font.m
@@ -22,7 +22,7 @@
 #import "cocoa/font.h"
 
 #import "css/css.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "render/font.h"
 #import "desktop/plotters.h"
 
diff --git a/cocoa/gui.m b/cocoa/gui.m
index fe92c52..b2ff01d 100644
--- a/cocoa/gui.m
+++ b/cocoa/gui.m
@@ -28,7 +28,7 @@
 #import "desktop/gui.h"
 #import "desktop/netsurf.h"
 #import "desktop/browser_private.h"
-#import "desktop/options.h"
+#import "utils/nsoption.h"
 #import "desktop/textinput.h"
 #import "desktop/401login.h"
 #import "utils/utils.h"
diff --git a/cocoa/system_colour.m b/cocoa/system_colour.m
deleted file mode 100644
index bd3e87f..0000000
--- a/cocoa/system_colour.m
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#import "utils/utils.h"
-#import "utils/log.h"
-#import "desktop/gui.h"
-#import "desktop/options.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ActiveBorder), 
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ActiveCaption), 
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_colour(sys_colour_AppWorkspace), 
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_colour(sys_colour_Background), 
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ButtonFace), 
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ButtonHighlight), 
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_colour(sys_colour_ButtonShadow), 
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_ButtonText), 
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_CaptionText), 
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_GrayText), 
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_colour(sys_colour_Highlight), 
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_HighlightText), 
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveBorder), 
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_colour(sys_colour_InactiveCaption), 
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_colour(sys_colour_InactiveCaptionText), 
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_InfoBackground), 
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_InfoText), 
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Menu), 
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_MenuText), 
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Scrollbar), 
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_colour(sys_colour_ThreeDDarkShadow), 
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_colour(sys_colour_ThreeDFace), 
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_ThreeDHighlight), 
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_colour(sys_colour_ThreeDLightShadow), 
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_colour(sys_colour_ThreeDShadow), 
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_colour(sys_colour_Window), 
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowFrame), 
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_colour(sys_colour_WindowText), 
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
diff --git a/content/content.c b/content/content.c
index 9bf4312..186c5be 100644
--- a/content/content.c
+++ b/content/content.c
@@ -37,7 +37,7 @@
 #include "css/css.h"
 #include "image/bitmap.h"
 #include "desktop/browser.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "render/html.h"
 #include "render/textplain.h"
 
@@ -188,6 +188,11 @@ nserror content_llcache_callback(llcache_handle *llcache,
 		msg_data.explicit_status_text = NULL;
 		content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
 		break;
+	case LLCACHE_EVENT_REDIRECT:
+		msg_data.redirect.from = event->data.redirect.from;
+		msg_data.redirect.to = event->data.redirect.to;
+		content_broadcast(c, CONTENT_MSG_REDIRECT, msg_data);
+		break;
 	}
 
 	return error;
diff --git a/content/content.h b/content/content.h
index 3e55888..467fa60 100644
--- a/content/content.h
+++ b/content/content.h
@@ -69,6 +69,7 @@ typedef enum {
 	CONTENT_MSG_DONE,      /**< finished */
 	CONTENT_MSG_ERROR,     /**< error occurred */
 	CONTENT_MSG_ERRORCODE, /**< error occurred return nserror */
+	CONTENT_MSG_REDIRECT,  /**< fetch url redirect occured */
 	CONTENT_MSG_STATUS,    /**< new status string */
 	CONTENT_MSG_REFORMAT,  /**< content_reformat done */
 	CONTENT_MSG_REDRAW,    /**< needs redraw (eg. new animation frame) */
@@ -103,6 +104,11 @@ union content_msg_data {
 	const char *error;
         /** CONTENT_MSG_ERRORCODE - Error code */
 	nserror errorcode;
+        /** CONTENT_MSG_REDIRECT - Redirect info */
+	struct {
+		nsurl *from;	/**< Redirect origin */
+		nsurl *to;	/**< Redirect target */
+	} redirect;		/**< Fetch URL redirect occured */
 	/** CONTENT_MSG_REDRAW - Area of content which needs redrawing */
 	struct {
 		int x, y, width, height;
diff --git a/content/fetch.c b/content/fetch.c
index bfe4458..6f829bb 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -45,7 +45,7 @@
 #include "content/fetchers/file.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/nsurl.h"
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 387e32a..cac8b2b 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -47,7 +47,7 @@
 #include "content/fetchers/about.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/url.h"
@@ -331,12 +331,13 @@ static bool fetch_about_config_handler(struct fetch_about_context *ctx)
 			"</p>\n"
 			"<h1>NetSurf Browser Config</h1>\n"
 			"<table class=\"config\">\n"
-			"<tr><th></th><th></th><th></th></tr>\n");
+			"<tr><th>Option</th><th>Type</th><th>Provenance</th><th>Setting</th></tr>\n");
 
 	do {
-		res = nsoption_snoptionf(buffer + slen, sizeof buffer - slen,
-				opt_loop,
-				"<tr><th>%k</th><td>%t</td><td>%V</td></tr>\n");
+		res = nsoption_snoptionf(buffer + slen, 
+					 sizeof buffer - slen,
+					 opt_loop,
+					 "<tr><th>%k</th><td>%t</td><td>%p</td><td>%V</td></tr>\n");
 		if (res <= 0) 
 			break; /* last option */
 
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index 668e05a..28c0f60 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -45,7 +45,7 @@
 #include "content/fetchers/curl.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/schedule.h"
@@ -613,11 +613,19 @@ fetch_curl_set_options(struct curl_fetch_info *f)
 		SETOPT(CURLOPT_USERPWD, NULL);
 	}
 
+	/* set up proxy options */
 	if (nsoption_bool(http_proxy) && 
 	    (nsoption_charp(http_proxy_host) != NULL) &&
 	    (strncmp(nsurl_access(f->url), "file:", 5) != 0)) {
 		SETOPT(CURLOPT_PROXY, nsoption_charp(http_proxy_host));
 		SETOPT(CURLOPT_PROXYPORT, (long) nsoption_int(http_proxy_port));
+
+#if LIBCURL_VERSION_NUM >= 0x071304
+		/* Added in 7.19.4 */
+		/* setup the omission list */
+		SETOPT(CURLOPT_NOPROXY, nsoption_charp(http_proxy_noproxy));
+#endif
+
 		if (nsoption_int(http_proxy_auth) != OPTION_HTTP_PROXY_AUTH_NONE) {
 			SETOPT(CURLOPT_PROXYAUTH,
 			       nsoption_int(http_proxy_auth) ==
diff --git a/content/fetchers/data.c b/content/fetchers/data.c
index 77d3c9f..fbaa247 100644
--- a/content/fetchers/data.c
+++ b/content/fetchers/data.c
@@ -34,7 +34,7 @@
 #include "content/fetchers/data.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/url.h"
diff --git a/content/fetchers/file.c b/content/fetchers/file.c
index b7b831d..21cee79 100644
--- a/content/fetchers/file.c
+++ b/content/fetchers/file.c
@@ -47,7 +47,7 @@
 #include "content/fetchers/file.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/errors.h"
 #include "utils/log.h"
 #include "utils/messages.h"
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 1fc33f8..4afd443 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -42,7 +42,7 @@
 #include "content/fetchers/resource.h"
 #include "content/urldb.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/url.h"
diff --git a/content/hlcache.c b/content/hlcache.c
index e99f238..6c84d16 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -593,6 +593,17 @@ nserror hlcache_llcache_callback(llcache_handle *handle,
 		break;
 	case LLCACHE_EVENT_PROGRESS:
 		break;
+	case LLCACHE_EVENT_REDIRECT:
+		if (ctx->handle->cb != NULL) {
+			hlcache_event hlevent;
+
+			hlevent.type = CONTENT_MSG_REDIRECT;
+			hlevent.data.redirect.from = event->data.redirect.from;
+			hlevent.data.redirect.to = event->data.redirect.to;
+
+			ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
+		}
+		break;
 	}
 
 	return NSERROR_OK;
diff --git a/content/llcache.c b/content/llcache.c
index 938f1e8..f2e519f 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -1224,6 +1224,7 @@ static nserror llcache_fetch_redirect(llcache_object *object, const char *target
 	bool match;
 	/* Extract HTTP response code from the fetch object */
 	long http_code = fetch_http_code(object->fetch.fetch);
+	llcache_event event;
 
 	/* Abort fetch for this object */
 	fetch_abort(object->fetch.fetch);
@@ -1238,8 +1239,6 @@ static nserror llcache_fetch_redirect(llcache_object *object, const char *target
 	/* Forcibly stop redirecting if we've followed too many redirects */
 #define REDIRECT_LIMIT 10
 	if (object->fetch.redirect_count > REDIRECT_LIMIT) {
-		llcache_event event;
-
 		LOG(("Too many nested redirects"));
 
 		event.type = LLCACHE_EVENT_ERROR;
@@ -1254,6 +1253,18 @@ static nserror llcache_fetch_redirect(llcache_object *object, const char *target
 	if (error != NSERROR_OK)
 		return error;
 
+	/* Inform users of redirect */
+	event.type = LLCACHE_EVENT_REDIRECT;
+	event.data.redirect.from = object->url;
+	event.data.redirect.to = url;
+
+	error = llcache_send_event_to_users(object, &event);
+
+	if (error != NSERROR_OK) {
+		nsurl_unref(url);
+		return error;
+	}
+
 	/* Reject attempts to redirect from unvalidated to validated schemes
 	 * A "validated" scheme is one over which we have some guarantee that
 	 * the source is trustworthy. */
diff --git a/content/llcache.h b/content/llcache.h
index b596310..3d8232c 100644
--- a/content/llcache.h
+++ b/content/llcache.h
@@ -56,6 +56,8 @@ typedef enum {
 
 	LLCACHE_EVENT_ERROR,		/**< An error occurred during fetch */
 	LLCACHE_EVENT_PROGRESS,		/**< Fetch progress update */
+
+	LLCACHE_EVENT_REDIRECT		/**< Fetch URL redirect occured */
 } llcache_event_type;
 
 /** Low-level cache events */
@@ -67,6 +69,10 @@ typedef struct {
 			size_t len;	/**< Length of buffer, in bytes */
 		} data;			/**< Received data */
 		const char *msg;	/**< Error or progress message */
+		struct {
+			nsurl *from;	/**< Redirect origin */
+			nsurl *to;	/**< Redirect target */
+		} redirect;		/**< Fetch URL redirect occured */
 	} data;				/**< Event data */
 } llcache_event;
 
diff --git a/content/urldb.c b/content/urldb.c
index e3cc1d7..c950dcd 100644
--- a/content/urldb.c
+++ b/content/urldb.c
@@ -101,12 +101,13 @@
 #include "content/content.h"
 #include "content/urldb.h"
 #include "desktop/cookies.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/corestrings.h"
 #include "utils/filename.h"
 #include "utils/url.h"
 #include "utils/utils.h"
+#include "utils/bloom.h"
 
 struct cookie_internal_data {
 	char *name;		/**< Cookie name */
@@ -327,6 +328,17 @@ static int loaded_cookie_file_version;
 #define MIN_URL_FILE_VERSION 106
 #define URL_FILE_VERSION 106
 
+/* Bloom filter used for short-circuting the false case of "is this
+ * URL in the database?".  BLOOM_SIZE controls how large the filter is
+ * in bytes.  Primitive experimentation shows that for a filter of X
+ * bytes filled with X items, searching for X items not in the filter
+ * has a 5% false-positive rate.  We set it to 32kB, which should be
+ * enough for all but the largest databases, while not being shockingly
+ * wasteful on memory.
+ */
+static struct bloom_filter *url_bloom;
+#define BLOOM_SIZE (1024 * 32)
+
 /**
  * Import an URL database from file, replacing any existing database
  *
@@ -346,7 +358,10 @@ void urldb_load(const char *filename)
 
 	assert(filename);
 
-	LOG(("Loading URL file"));
+	LOG(("Loading URL file %s", filename));
+
+        if (url_bloom == NULL)
+                url_bloom = bloom_create(BLOOM_SIZE);
 
 	fp = fopen(filename, "r");
 	if (!fp) {
@@ -456,6 +471,11 @@ void urldb_load(const char *filename)
 				die("Memory exhausted whilst loading "
 						"URL file");
 			}
+                        
+			if (url_bloom != NULL) {
+				uint32_t hash = nsurl_hash(nsurl);
+				bloom_insert_hash(url_bloom, hash);
+			}
 
 			/* Copy and merge path/query strings */
 			if (nsurl_get(nsurl, NSURL_PATH | NSURL_QUERY,
@@ -782,6 +802,14 @@ bool urldb_add_url(nsurl *url)
 	unsigned int port_int;
 
 	assert(url);
+        
+        if (url_bloom == NULL)
+                url_bloom = bloom_create(BLOOM_SIZE);
+        
+        if (url_bloom != NULL) {
+                uint32_t hash = nsurl_hash(url);
+                bloom_insert_hash(url_bloom, hash);
+        }
 
 	/* Copy and merge path/query strings */
 	if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &path_query, &len) !=
@@ -1857,6 +1885,13 @@ struct path_data *urldb_find_url(nsurl *url)
 	bool match;
 
 	assert(url);
+        
+	if (url_bloom != NULL) {
+		if (bloom_search_hash(url_bloom,
+					nsurl_hash(url)) == false) {
+					return NULL;
+		}
+	}
 
 	scheme = nsurl_get_component(url, NSURL_SCHEME);
 	if (scheme == NULL)
@@ -3951,6 +3986,10 @@ void urldb_destroy(void)
 		b = a->next;
 		urldb_destroy_host_tree(a);
 	}
+        
+        /* And the bloom filter */
+        if (url_bloom != NULL)
+                bloom_destroy(url_bloom);
 }
 
 /**
diff --git a/css/select.c b/css/select.c
index b9b8c28..0f1962b 100644
--- a/css/select.c
+++ b/css/select.c
@@ -27,7 +27,7 @@
 #include "css/select.h"
 #include "css/utils.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/corestrings.h"
 #include "utils/log.h"
 #include "utils/url.h"
diff --git a/css/utils.c b/css/utils.c
index d5acf49..9bf743c 100644
--- a/css/utils.c
+++ b/css/utils.c
@@ -21,7 +21,7 @@
 
 #include "css/utils.h"
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 
 /** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
diff --git a/css/utils.h b/css/utils.h
index 9d40aba..f3131f1 100644
--- a/css/utils.h
+++ b/css/utils.h
@@ -27,17 +27,32 @@ extern css_fixed nscss_screen_dpi;
 
 /**
  * Convert a CSS color to a NetSurf colour primitive
- * 
+ *
  * ARGB -> (1-A)BGR
  *
  * \param color  The CSS color to convert
  * \return Corresponding NetSurf colour primitive
  */
-#define nscss_color_to_ns(color) \
-		(0xff000000 - ((color) & 0xff000000)) | \
-		(((color) & 0xff0000) >> 16) | \
-		((color) & 0xff00) | \
-		(((color) & 0xff) << 16)
+#define nscss_color_to_ns(c) \
+		( ((~c) & 0xff000000)        | \
+		 ((( c) & 0xff0000  ) >> 16) | \
+		  (( c) & 0xff00    )        | \
+		 ((( c) & 0xff      ) << 16))
+
+
+/**
+ * Convert a NetSurf color to a CSS colour primitive
+ *
+ * (1-A)BGR -> ARGB
+ *
+ * \param color  The NetSurf color to convert
+ * \return Corresponding CSS colour primitive
+ */
+#define ns_color_to_nscss(c) \
+		( ((~c) & 0xff000000)        | \
+		 ((( c) & 0xff0000  ) >> 16) | \
+		  (( c) & 0xff00    )        | \
+		 ((( c) & 0xff      ) << 16))
 
 /**
  * Determine if a CSS color primitive is transparent
diff --git a/desktop/Makefile b/desktop/Makefile
index b587e67..f91754e 100644
--- a/desktop/Makefile
+++ b/desktop/Makefile
@@ -1,9 +1,9 @@
 # Sources for desktop
 
 S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c	\
-	mouse.c options.c plot_style.c print.c search.c searchweb.c	\
+	mouse.c plot_style.c print.c search.c searchweb.c	\
 	scrollbar.c sslcert.c textarea.c thumbnail.c tree.c 		\
-	tree_url_node.c version.c
+	tree_url_node.c version.c system_colour.c
 
 S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP))
 
diff --git a/desktop/browser.c b/desktop/browser.c
index 12cc9c8..b7ec989 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -49,7 +49,7 @@
 #include "desktop/hotlist.h"
 #include "desktop/gui.h"
 #include "desktop/knockout.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/scrollbar.h"
 #include "desktop/selection.h"
 #include "desktop/plotters.h"
@@ -683,6 +683,19 @@ void browser_window_debug_dump(struct browser_window *bw, FILE *f)
 		content_debug_dump(bw->current_content, f);
 }
 
+/** slow script handler
+*/
+static bool slow_script(void *ctx)
+{
+	static int count = 0;
+	LOG(("Continuing execution %d", count));
+	count++;
+	if (count > 1) {
+		count = 0;
+		return false;
+	}
+	return true;
+}
 
 /* exported interface, documented in desktop/browser.h */
 
@@ -707,7 +720,9 @@ browser_window_create(enum browser_window_nav_flags flags,
 	}
 
 	/* new javascript context for window */
-	bw->jsctx = js_newcontext();
+	bw->jsctx = js_newcontext(nsoption_int(script_timeout),
+				  slow_script,
+				  NULL);
 
 	/* Initialise common parts */
 	browser_window_initialise_common(bw, clone);
@@ -1340,6 +1355,11 @@ nserror browser_window_callback(hlcache_handle *c,
 		browser_window_stop_throbber(bw);
 		break;
 
+	case CONTENT_MSG_REDIRECT:
+		if (urldb_add_url(event->data.redirect.from))
+			urldb_update_url_visit_data(event->data.redirect.from);
+		break;
+
 	case CONTENT_MSG_STATUS:
 		if (event->data.explicit_status_text == NULL) {
 			/* Object content's status text updated */
diff --git a/desktop/cookies.c b/desktop/cookies.c
index 197b3fb..9f66aea 100644
--- a/desktop/cookies.c
+++ b/desktop/cookies.c
@@ -31,7 +31,7 @@
 #include "content/hlcache.h"
 #include "content/urldb.h"
 #include "desktop/cookies.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/tree.h"
 #include "utils/log.h"
 #include "utils/messages.h"
diff --git a/desktop/download.c b/desktop/download.c
index f4bedc8..b775eb1 100644
--- a/desktop/download.c
+++ b/desktop/download.c
@@ -238,6 +238,9 @@ static nserror download_callback(llcache_handle *handle,
 
 	case LLCACHE_EVENT_PROGRESS:
 		break;
+
+	case LLCACHE_EVENT_REDIRECT:
+		break;
 	}
 
 	return error;
diff --git a/desktop/gui.h b/desktop/gui.h
index f4b8b72..dc19095 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -64,10 +64,6 @@ struct form_control;
 #include "desktop/search.h"
 #include "utils/errors.h"
 
-/** \todo remove these when each frontend calls nslog_init */
-#include <stdio.h>
-bool nslog_ensure(FILE *fptr);
-
 void gui_poll(bool active);
 void gui_quit(void);
 
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 0b1cffe..fa026dc 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -40,7 +40,7 @@
 #include "desktop/401login.h"
 #include "desktop/browser.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/searchweb.h"
 
 #include "javascript/js.h"
@@ -115,10 +115,7 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query,
  * Initialise components used by gui NetSurf.
  */
 
-nserror netsurf_init(int *pargc, 
-		     char ***pargv, 
-		     const char *options, 
-		     const char *messages)
+nserror netsurf_init(const char *messages)
 {
 	nserror error;
 	struct utsname utsname;
@@ -138,24 +135,12 @@ nserror netsurf_init(int *pargc,
 	 * way of determining the cause of the SIGPIPE (other than using
 	 * sigaction() and some mechanism for getting the file descriptor
 	 * out of libcurl). However, we expect nothing else to generate a
-	 * SIGPIPE, anyway, so may as well just ignore them all. */
-	
+	 * SIGPIPE, anyway, so may as well just ignore them all.
+	 */
 	signal(SIGPIPE, SIG_IGN);
 #endif
 
-#ifndef HAVE_STDOUT
-	ret = nslog_init(nslog_ensure, pargc, *pargv);
-#else
-	ret = nslog_init(NULL, pargc, *pargv);
-#endif
-
-	if (ret != NSERROR_OK) 
-		return ret;
-
-#ifdef _MEMDEBUG_H_
-	memdebug_memdebug("memdump");
-#endif
-	LOG(("version '%s'", netsurf_version));
+	LOG(("NetSurf version '%s'", netsurf_version));
 	if (uname(&utsname) < 0)
 		LOG(("Failed to extract machine information"));
 	else
@@ -164,10 +149,6 @@ nserror netsurf_init(int *pargc,
 				utsname.nodename, utsname.release,
 				utsname.version, utsname.machine));
 
-	LOG(("Using '%s' for Options file", options));
-	nsoption_read(options);
-	gui_options_init_defaults();
-
 	messages_load(messages);
 
 	/* corestrings init */
@@ -187,7 +168,7 @@ nserror netsurf_init(int *pargc,
 	/* image cache is 25% of total memory cache size */
 	image_cache_parameters.limit = (hlcache_parameters.limit * 25) / 100;
 
-	/* image cache hysteresis is 20% of teh image cache size */
+	/* image cache hysteresis is 20% of the image cache size */
 	image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100;
 
 	/* account for image cache use from total */
@@ -232,8 +213,6 @@ nserror netsurf_init(int *pargc,
 	/* Initialize system colours */
 	gui_system_colour_init();
 
-	nsoption_commandline(pargc, *pargv);
-
 	js_initialise();
 
 	return ret;
diff --git a/desktop/netsurf.h b/desktop/netsurf.h
index 10c1e00..bfdb647 100644
--- a/desktop/netsurf.h
+++ b/desktop/netsurf.h
@@ -28,7 +28,7 @@ extern const char * const netsurf_version;
 extern const int netsurf_version_major;
 extern const int netsurf_version_minor;
 
-nserror netsurf_init(int *argc, char ***argv, const char *options, const char *messages);
+nserror netsurf_init(const char *messages);
 extern void netsurf_exit(void);
 extern int netsurf_main_loop(void);
 
diff --git a/desktop/options.c b/desktop/options.c
deleted file mode 100644
index 2a080d5..0000000
--- a/desktop/options.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright 2003 Phil Mellor <monkeyson at users.sourceforge.net>
- * Copyright 2003 John M Bell <jmb202 at ecs.soton.ac.uk>
- * Copyright 2004 James Bursa <bursa at users.sourceforge.net>
- * Copyright 2005 Richard Wilson <info at tinct.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Option reading and saving (implementation).
- *
- * Options are stored in the format key:value, one per line. For bool options,
- * value is "0" or "1".
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-
-#include "css/css.h"
-#include "desktop/plot_style.h"
-#include "utils/log.h"
-#include "utils/utils.h"
-#include "desktop/options.h"
-
-struct ns_options nsoptions = {
-	NSOPTION_MAIN_DEFAULTS,
-	NSOPTION_SYS_COLOUR_DEFAULTS,
-	NSOPTION_EXTRA_DEFAULTS
-};
-
-enum option_type_e {
-	OPTION_BOOL,
-	OPTION_INTEGER,
-	OPTION_STRING,
-	OPTION_COLOUR
-} ;
-
-struct option_entry_s {
-	const char *key;
-	enum option_type_e type;
-	void *p;
-};
-
-struct option_entry_s option_table[] = {
-	NSOPTION_MAIN_TABLE,
-	NSOPTION_EXTRA_TABLE
-};
-
-#define option_table_entries (sizeof option_table / sizeof option_table[0])
-
-/**
- * Set an option value based on a string
- */
-static bool 
-strtooption(const char *value, struct option_entry_s *option_entry)
-{
-	bool ret = false;
-	colour rgbcolour; /* RRGGBB */
-
-	switch (option_entry->type) {
-	case OPTION_BOOL:
-		*((bool *)option_entry->p) = value[0] == '1';
-		ret = true;
-		break;
-
-	case OPTION_INTEGER:
-		*((int *)option_entry->p) = atoi(value);
-		ret = true;
-		break;
-
-	case OPTION_COLOUR:
-		sscanf(value, "%x", &rgbcolour);
-		*((colour *)option_entry->p) =
-			((0x000000FF & rgbcolour) << 16) |
-			((0x0000FF00 & rgbcolour) << 0) |
-			((0x00FF0000 & rgbcolour) >> 16);
-		ret = true;
-		break;
-
-	case OPTION_STRING:
-		free(*((char **)option_entry->p));
-		if (*value == 0) {
-			/* do not allow empty strings in text options */
-			*((char **)option_entry->p) = NULL;
-		} else {
-			*((char **)option_entry->p) = strdup(value);
-		}
-		ret = true;
-		break;
-	}
-
-	return ret;
-}
-
-static void nsoptions_validate(struct ns_options *opts)
-{
-	if (opts->font_size < 50)
-		opts->font_size = 50;
-
-	if (1000 < opts->font_size)
-		opts->font_size = 1000;
-
-	if (opts->font_min_size < 10)
-		opts->font_min_size = 10;
-
-	if (500 < opts->font_min_size)
-		opts->font_min_size = 500;
-
-	if (opts->memory_cache_size < 0)
-		opts->memory_cache_size = 0;
-
-}
-
-/* exported interface documented in options.h */
-void nsoption_read(const char *path)
-{
-	char s[100];
-	FILE *fp;
-
-	if (path == NULL) {
-		LOG(("No options loaded"));
-		return;
-	}
-
-	fp = fopen(path, "r");
-	if (!fp) {
-		LOG(("failed to open file '%s'", path));
-		return;
-	}
-
-	while (fgets(s, 100, fp)) {
-		char *colon, *value;
-		unsigned int i;
-
-		if (s[0] == 0 || s[0] == '#')
-			continue;
-		colon = strchr(s, ':');
-		if (colon == 0)
-			continue;
-		s[strlen(s) - 1] = 0;  /* remove \n at end */
-		*colon = 0;  /* terminate key */
-		value = colon + 1;
-
-		for (i = 0; i != option_table_entries; i++) {
-			if (strcasecmp(s, option_table[i].key) != 0)
-				continue;
-
-			strtooption(value, option_table + i);
-			break;
-		}
-	}
-
-	fclose(fp);
-
-	nsoptions_validate(&nsoptions);
-}
-
-
-/* exported interface documented in options.h */
-void nsoption_write(const char *path)
-{
-	unsigned int entry;
-	FILE *fp;
-	colour rgbcolour; /* RRGGBB */
-
-	fp = fopen(path, "w");
-	if (!fp) {
-		LOG(("failed to open file '%s' for writing", path));
-		return;
-	}
-
-	for (entry = 0; entry != option_table_entries; entry++) {
-		switch (option_table[entry].type) {
-		case OPTION_BOOL:
-			fprintf(fp, "%s:%c\n", option_table[entry].key, 
-				*((bool *) option_table[entry].p) ? '1' : '0');
-			break;
-
-		case OPTION_INTEGER:
-			fprintf(fp, "%s:%i\n", option_table[entry].key, 
-				*((int *) option_table[entry].p));
-			break;
-
-		case OPTION_COLOUR:
-			rgbcolour = ((0x000000FF & *((colour *)
-					option_table[entry].p)) << 16) |
-				((0x0000FF00 & *((colour *)
-					option_table[entry].p)) << 0) |
-				((0x00FF0000 & *((colour *)
-					option_table[entry].p)) >> 16);
-			fprintf(fp, "%s:%06x\n", option_table[entry].key, 
-				rgbcolour);
-			break;
-
-		case OPTION_STRING:
-			if (((*((char **) option_table[entry].p)) != NULL) && 
-			    (*(*((char **) option_table[entry].p)) != 0)) {
-				fprintf(fp, "%s:%s\n", option_table[entry].key,
-					*((char **) option_table[entry].p));
-			}
-			break;
-		}
-	}
-
-	fclose(fp);
-}
-
-
-/**
- * Output an option value into a string, in HTML format.
- *
- * \param option  The option to output the value of.
- * \param size    The size of the string buffer.
- * \param pos     The current position in string
- * \param string  The string in which to output the value.
- * \return The number of bytes written to string or -1 on error
- */
-static size_t 
-nsoption_output_value_html(struct option_entry_s *option,
-		size_t size, size_t pos, char *string)
-{
-	size_t slen = 0; /* length added to string */
-	colour rgbcolour; /* RRGGBB */
-
-	switch (option->type) {
-	case OPTION_BOOL:
-		slen = snprintf(string + pos, size - pos, "%s",
-				*((bool *)option->p) ? "true" : "false");
-		break;
-
-	case OPTION_INTEGER:
-		slen = snprintf(string + pos, size - pos, "%i",
-				*((int *)option->p));
-		break;
-
-	case OPTION_COLOUR:
-		rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) |
-				((0x0000FF00 & *((colour *) option->p)) << 0) |
-				((0x00FF0000 & *((colour *) option->p)) >> 16);
-		slen = snprintf(string + pos, size - pos,
-				"<span style=\"background-color: #%06x; "
-				"color: #%06x;\">#%06x</span>", rgbcolour,
-				(~rgbcolour) & 0xffffff, rgbcolour);
-		break;
-
-	case OPTION_STRING:
-		if (*((char **)option->p) != NULL) {
-			slen = snprintf(string + pos, size - pos, "%s",
-					*((char **)option->p));
-		} else {
-			slen = snprintf(string + pos, size - pos,
-					"<span class=\"null-content\">NULL"
-					"</span>");
-		}
-		break;
-	}
-
-	return slen;
-}
-
-
-/**
- * Output an option value into a string, in plain text format.
- *
- * \param option  The option to output the value of.
- * \param size    The size of the string buffer.
- * \param pos     The current position in string
- * \param string  The string in which to output the value.
- * \return The number of bytes written to string or -1 on error
- */
-static size_t 
-nsoption_output_value_text(struct option_entry_s *option,
-		size_t size, size_t pos, char *string)
-{
-	size_t slen = 0; /* length added to string */
-	colour rgbcolour; /* RRGGBB */
-
-	switch (option->type) {
-	case OPTION_BOOL:
-		slen = snprintf(string + pos, size - pos, "%c",
-				*((bool *)option->p) ? '1' : '0');
-		break;
-
-	case OPTION_INTEGER:
-		slen = snprintf(string + pos, size - pos, "%i",
-				*((int *)option->p));
-		break;
-
-	case OPTION_COLOUR:
-		rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) |
-				((0x0000FF00 & *((colour *) option->p)) << 0) |
-				((0x00FF0000 & *((colour *) option->p)) >> 16);
-		slen = snprintf(string + pos, size - pos, "%06x", rgbcolour);
-		break;
-
-	case OPTION_STRING:
-		if (*((char **)option->p) != NULL) {
-			slen = snprintf(string + pos, size - pos, "%s",
-					*((char **)option->p));
-		}
-		break;
-	}
-
-	return slen;
-}
-
-/* exported interface documented in options.h */
-void 
-nsoption_commandline(int *pargc, char **argv)
-{
-	char *arg;
-	char *val;
-	int arglen;
-	int idx = 1;
-	int mv_loop;
-
-	unsigned int entry_loop;
-
-	while (idx < *pargc) {
-		arg = argv[idx];
-		arglen = strlen(arg);
-
-		/* check we have an option */
-		/* option must start -- and be as long as the shortest option*/
-		if ((arglen < (2+5) ) || (arg[0] != '-') || (arg[1] != '-'))
-			break;
-
-		arg += 2; /* skip -- */
-
-		val = strchr(arg, '=');
-		if (val == NULL) {
-			/* no equals sign - next parameter is val */
-			idx++;
-			if (idx >= *pargc)
-				break;
-			val = argv[idx];
-		} else {
-			/* equals sign */
-			arglen = val - arg ;
-			val++;
-		}
-
-		/* arg+arglen is the option to set, val is the value */
-
-		LOG(("%.*s = %s",arglen,arg,val));
-
-		for (entry_loop = 0; 
-		     entry_loop < option_table_entries; 
-		     entry_loop++) {
-			if (strncmp(arg, option_table[entry_loop].key, 
-				    arglen) == 0) { 
-				strtooption(val, option_table + entry_loop);
-				break;
-			}			
-		}
-
-		idx++;
-	}
-
-	/* remove processed options from argv */
-	for (mv_loop=0;mv_loop < (*pargc - idx); mv_loop++) {
-		argv[mv_loop + 1] = argv[mv_loop + idx];
-	}
-	*pargc -= (idx - 1);
-}
-
-/* exported interface documented in options.h */
-int 
-nsoption_snoptionf(char *string, size_t size, unsigned int option, const char *fmt)
-{
-	size_t slen = 0; /* current output string length */
-	int fmtc = 0; /* current index into format string */
-	struct option_entry_s *option_entry;
-
-	if (option >= option_table_entries)
-		return -1;
-
-	option_entry = option_table + option;
-
-	while((slen < size) && (fmt[fmtc] != 0)) {
-		if (fmt[fmtc] == '%') {
-			fmtc++;
-			switch (fmt[fmtc]) {
-			case 'k':
-				slen += snprintf(string + slen, size - slen,
-						"%s", option_entry->key);
-				break;
-
-			case 't':
-				switch (option_entry->type) {
-				case OPTION_BOOL:
-					slen += snprintf(string + slen,
-							 size - slen,
-							 "boolean");
-					break;
-
-				case OPTION_INTEGER:
-					slen += snprintf(string + slen,
-							 size - slen,
-							 "integer");
-					break;
-
-				case OPTION_COLOUR:
-					slen += snprintf(string + slen,
-							 size - slen,
-							 "colour");
-					break;
-
-				case OPTION_STRING:
-					slen += snprintf(string + slen,
-							 size - slen,
-							 "string");
-					break;
-
-				}
-				break;
-
-
-			case 'V':
-				slen += nsoption_output_value_html(option_entry,
-						size, slen, string);
-				break;
-			case 'v':
-				slen += nsoption_output_value_text(option_entry,
-						size, slen, string);
-				break;
-			}
-			fmtc++;
-		} else {
-			string[slen] = fmt[fmtc];
-			slen++;
-			fmtc++;
-		}
-	}
-
-	/* Ensure that we NUL-terminate the output */
-	string[min(slen, size - 1)] = '\0';
-
-	return slen;
-}
-
-/* exported interface documented in options.h */
-void 
-nsoption_dump(FILE *outf)
-{
-	char buffer[256];
-	int opt_loop = 0;
-	int res;
-
-	do {
-		res = nsoption_snoptionf(buffer, sizeof buffer, opt_loop,
-				"%k:%v\n");
-		if (res > 0) {
-			fprintf(outf, "%s", buffer);
-		}
-		opt_loop++;
-	} while (res > 0);
-}
-
diff --git a/desktop/options.h b/desktop/options.h
index 17ba64f..391dfbc 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -1,6 +1,5 @@
 /*
- * Copyright 2003 Phil Mellor <monkeyson at users.sourceforge.net>
- * Copyright 2004 James Bursa <bursa at users.sourceforge.net>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -18,171 +17,261 @@
  */
 
 /** \file
- * Option reading and saving (interface).
+ * Option available on all platforms
  *
- * Non-platform specific options can be added by editing this file and
- * netsurf/desktop/options.c
+ * Non-platform specific options can be added by editing this file 
  *
  * Platform specific options should be added in the platform options.h.
  *
- * The following types of options are supported:
- *  - bool (OPTION_BOOL)
- *  - int (OPTION_INTEGER)
- *  - char* (OPTION_STRING) (must be allocated on heap, may be 0, free before
- *                           assigning a new value)
+ * This header is specificaly intented to be included multiple times
+ *   with different macro definitions so there is no guard
  */
 
 #ifndef _NETSURF_DESKTOP_OPTIONS_H_
 #define _NETSURF_DESKTOP_OPTIONS_H_
 
-#define _NETSURF_DESKTOP_OPTIONS_INCLUDING_
+#include "desktop/plot_style.h"
 
-#include <stdbool.h>
-#include <stdio.h>
+/* defines for system colour table */
+#define NSOPTION_SYS_COLOUR_START NSOPTION_sys_colour_ActiveBorder
+#define NSOPTION_SYS_COLOUR_END NSOPTION_sys_colour_WindowText
 
-#include "desktop/plot_style.h"
-#include "desktop/options_main.h"
-
-#if defined(riscos)
-#include "riscos/options.h"
-#elif defined(nsgtk)
-#include "gtk/options.h"
-#elif defined(nsbeos)
-#include "beos/options.h"
-#elif defined(nsamiga)
-#include "amiga/options.h"
-#elif defined(nsframebuffer)
-#include "framebuffer/options.h"
-#elif defined(nsatari)
-#include "atari/options.h"
-#elif defined(nsmonkey)
-#include "monkey/options.h"
-#else
-#define NSOPTION_EXTRA_DEFINE
-#define NSOPTION_EXTRA_DEFAULTS
-#define NSOPTION_EXTRA_TABLE
 #endif
 
-/* allow the colour defaults to be overidden by the frontends */
-#ifndef NSOPTION_SYS_COLOUR_DEFAULTS
-#define NSOPTION_SYS_COLOUR_DEFAULTS NSOPTION_MAIN_SYS_COLOUR_DEFAULTS
-#endif
+/** An HTTP proxy should be used. */
+NSOPTION_BOOL(http_proxy, false) 
 
-#undef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
+/** Hostname of proxy. */
+NSOPTION_STRING(http_proxy_host, NULL) 
 
+/** Proxy port. */
+NSOPTION_INTEGER(http_proxy_port, 8080) 
 
-enum { OPTION_HTTP_PROXY_AUTH_NONE = 0,
-       OPTION_HTTP_PROXY_AUTH_BASIC = 1,
-       OPTION_HTTP_PROXY_AUTH_NTLM = 2 };
+/** Proxy authentication method. */
+NSOPTION_INTEGER(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NONE) 
 
-#define DEFAULT_MARGIN_TOP_MM 10
-#define DEFAULT_MARGIN_BOTTOM_MM 10
-#define DEFAULT_MARGIN_LEFT_MM 10
-#define DEFAULT_MARGIN_RIGHT_MM 10
-#define DEFAULT_EXPORT_SCALE 0.7
-#ifdef riscos
-#define DEFAULT_REFLOW_PERIOD 100 /* time in cs */
-#else
-#define DEFAULT_REFLOW_PERIOD 25 /* time in cs */
-#endif
+/** Proxy authentication user name */
+NSOPTION_STRING(http_proxy_auth_user, NULL)
 
-struct ns_options {
-	NSOPTION_MAIN_DEFINE;
-	NSOPTION_EXTRA_DEFINE;
-};
-
-/* global option struct */
-extern struct ns_options nsoptions;
-
-/* acessors */
-#define nsoption_bool(OPTION) (nsoptions.OPTION)
-#define nsoption_int(OPTION) (nsoptions.OPTION)
-#define nsoption_charp(OPTION) (nsoptions.OPTION)
-#define nsoption_colour(OPTION) (nsoptions.OPTION)
-
-#define nsoption_set_bool(OPTION, VALUE) nsoptions.OPTION = VALUE
-#define nsoption_set_int(OPTION, VALUE) nsoptions.OPTION = VALUE
-#define nsoption_set_colour(OPTION, VALUE) nsoptions.OPTION = VALUE
-#define nsoption_set_charp(OPTION, VALUE) do {	\
-	if (nsoptions.OPTION != NULL) {		\
-		free(nsoptions.OPTION);		\
-	}					\
-	nsoptions.OPTION = VALUE;               \
-        if ((nsoptions.OPTION != NULL) &&	\
-	    (*nsoptions.OPTION == 0)) {		\
-            free(nsoptions.OPTION);             \
-            nsoptions.OPTION = NULL;            \
-        }                                       \
-    } while (0)
-
-#define nsoption_setnull_charp(OPTION, VALUE)           \
-    do {                                                \
-        if (nsoptions.OPTION == NULL) {                 \
-            nsoptions.OPTION = VALUE;                   \
-            if (*nsoptions.OPTION == 0) {               \
-                free(nsoptions.OPTION);                 \
-                nsoptions.OPTION = NULL;                \
-            }                                           \
-        } else {                                        \
-            free(VALUE);                                \
-        }                                               \
-    } while (0)
-
-
-/**
- * Read options from a file.
- *
- * \param  path  name of file to read options from
- *
- * Option variables corresponding to lines in the file are updated. Missing
- * options are unchanged. If the file fails to open, options are unchanged.
- */
-void nsoption_read(const char *path);
+/** Proxy authentication password */
+NSOPTION_STRING(http_proxy_auth_pass, NULL)
 
-/**
- * Save options to a file.
- *
- * \param  path  name of file to write options to
- *
- * Errors are ignored.
- */
-void nsoption_write(const char *path);
+/** Proxy omission list */
+NSOPTION_STRING(http_proxy_noproxy, "localhost")
 
-/**
- * Dump user options to stream
- *
- * \param outf output stream to dump options to.
- */
-void nsoption_dump(FILE *outf);
+/** Default font size / 0.1pt. */
+NSOPTION_INTEGER(font_size, 128)
 
-/**
- * Fill a buffer with an option using a format.
- *
- * The format string is copied into the output buffer with the
- * following replaced:
- * %k - The options key
- * %t - The options type
- * %V - value - HTML type formatting
- * %v - value - plain formatting
- *
- * \param string  The buffer in which to place the results.
- * \param size    The size of the string buffer.
- * \param option  The opaque option number.
- * \param fmt     The format string.
- * \return The number of bytes written to \a string or -1 on error
- */
-int nsoption_snoptionf(char *string, size_t size, unsigned int option,
-		const char *fmt);
+/** Minimum font size. */
+NSOPTION_INTEGER(font_min_size, 85)
+
+/** Default sans serif font */
+NSOPTION_STRING(font_sans, NULL)
+/** Default serif font */
+NSOPTION_STRING(font_serif, NULL)
+
+/** Default monospace font */
+NSOPTION_STRING(font_mono, NULL)
+
+/** Default cursive font */
+NSOPTION_STRING(font_cursive, NULL)
+
+/** Default fantasy font */
+NSOPTION_STRING(font_fantasy, NULL)
+
+/** Accept-Language header. */
+NSOPTION_STRING(accept_language, NULL)
+
+/** Accept-Charset header. */
+NSOPTION_STRING(accept_charset, NULL)
+
+/** Preferred maximum size of memory cache / bytes. */
+NSOPTION_INTEGER(memory_cache_size, 12 * 1024 * 1024)
+
+/** Preferred expiry size of disc cache / bytes. */
+NSOPTION_INTEGER(disc_cache_size, 1024 * 1024 * 1024)
+
+/** Preferred expiry age of disc cache / days. */
+NSOPTION_INTEGER(disc_cache_age, 28)
+
+/** Whether to block advertisements */
+NSOPTION_BOOL(block_advertisements, false)
+
+/** Disable website tracking, see	                
+ * http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */
+NSOPTION_BOOL(do_not_track, false)
+
+/** Minimum GIF animation delay */
+NSOPTION_INTEGER(minimum_gif_delay, 10)
+
+/** Whether to send the referer HTTP header */
+NSOPTION_BOOL(send_referer, true)
+
+/** Whether to fetch foreground images */
+NSOPTION_BOOL(foreground_images, true)
+
+/** Whether to fetch background images */
+NSOPTION_BOOL(background_images, true)
+
+/** Whether to animate images */
+NSOPTION_BOOL(animate_images, true)
+
+/** Whether to execute javascript */
+NSOPTION_BOOL(enable_javascript, false)
+
+/** Maximum time (in seconds) to wait for a script to run */
+NSOPTION_INTEGER(script_timeout, 10)
+
+/** How many days to retain URL data for */
+NSOPTION_INTEGER(expire_url, 28)
+
+/** Default font family */
+NSOPTION_INTEGER(font_default, PLOT_FONT_FAMILY_SANS_SERIF)
 
-/**
- * Process commandline and set options approriately.
+/** ca-bundle location */
+NSOPTION_STRING(ca_bundle, NULL)
+
+/** ca-path location */
+NSOPTION_STRING(ca_path, NULL)
+
+/** Cookie file location */
+NSOPTION_STRING(cookie_file, NULL)
+
+/** Cookie jar location */
+NSOPTION_STRING(cookie_jar, NULL)
+
+/** Home page location */
+NSOPTION_STRING(homepage_url, NULL)
+
+/** search web from url bar */
+NSOPTION_BOOL(search_url_bar, false)
+
+/** default web search provider */
+NSOPTION_INTEGER(search_provider, 0)
+
+/** URL completion in url bar */
+NSOPTION_BOOL(url_suggestion, true)
+
+/** default x position of new windows */
+NSOPTION_INTEGER(window_x, 0)
+
+/** default y position of new windows */
+NSOPTION_INTEGER(window_y, 0)
+
+/** default width of new windows */
+NSOPTION_INTEGER(window_width, 0)
+
+/** default height of new windows */
+NSOPTION_INTEGER(window_height, 0)
+
+/** width of screen when above options were saved */
+NSOPTION_INTEGER(window_screen_width, 0)
+
+/** height of screen when above options were saved */
+NSOPTION_INTEGER(window_screen_height, 0)
+
+/** default size of status bar vs. h scroll bar */
+NSOPTION_INTEGER(toolbar_status_size, 6667)
+
+/** default window scale */
+NSOPTION_INTEGER(scale, 100)
+
+/* Whether to reflow web pages while objects are fetching */
+NSOPTION_BOOL(incremental_reflow, true)
+
+/* Minimum time (in cs) between HTML reflows while objects are fetching */
+NSOPTION_UINT(min_reflow_period, DEFAULT_REFLOW_PERIOD)
+
+/* use core selection menu */
+NSOPTION_BOOL(core_select_menu, false)
+
+/******** Fetcher options ********/
+
+/** Maximum simultaneous active fetchers */
+NSOPTION_INTEGER(max_fetchers, 24)
+
+/** Maximum simultaneous active fetchers per host.
+ * (<=option_max_fetchers else it makes no sense) Note that rfc2616
+ * section 8.1.4 says that there should be no more than two keepalive
+ * connections per host. None of the main browsers follow this as it
+ * slows page fetches down considerably.  See
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4
  */
-void nsoption_commandline(int *pargc, char **argv);
+NSOPTION_INTEGER(max_fetchers_per_host, 5)
 
-/**
- * Set default values for unset front-end specific options
+/** Maximum number of inactive fetchers cached.  The total number of
+ * handles netsurf will therefore have open is this plus
+ * option_max_fetchers.
  */
-void gui_options_init_defaults(void);
+NSOPTION_INTEGER(max_cached_fetch_handles, 6)
 
-#endif
+/** Suppress debug output from cURL. */
+NSOPTION_BOOL(suppress_curl_debug, true)
+
+/** Whether to allow target="_blank" */
+NSOPTION_BOOL(target_blank, true)
+
+/** Whether second mouse button opens in new tab */
+NSOPTION_BOOL(button_2_tab, true)
+
+/******** PDF / Print options ********/
+
+/** top margin of exported page */
+NSOPTION_INTEGER(margin_top, DEFAULT_MARGIN_TOP_MM)
+
+/** bottom margin of exported page */
+NSOPTION_INTEGER(margin_bottom, DEFAULT_MARGIN_BOTTOM_MM)
+
+/** left margin of exported page */
+NSOPTION_INTEGER(margin_left, DEFAULT_MARGIN_LEFT_MM)
+
+/** right margin of exported page */
+NSOPTION_INTEGER(margin_right, DEFAULT_MARGIN_RIGHT_MM)
+
+/** scale of exported content */
+NSOPTION_INTEGER(export_scale, DEFAULT_EXPORT_SCALE * 100)
+
+/** suppressing images in printed content */
+NSOPTION_BOOL(suppress_images, false)
+
+/** turning off all backgrounds for printed content */
+NSOPTION_BOOL(remove_backgrounds, false)
+
+/** turning on content loosening for printed content */
+NSOPTION_BOOL(enable_loosening, true)
+
+/** compression of PDF documents */
+NSOPTION_BOOL(enable_PDF_compression, true)
+
+/** setting a password and encoding PDF documents */
+NSOPTION_BOOL(enable_PDF_password, false)
 
+/******** System colours ********/
+NSOPTION_COLOUR(sys_colour_ActiveBorder, 0x00d3d3d3)
+NSOPTION_COLOUR(sys_colour_ActiveCaption, 0x00f1f1f1)
+NSOPTION_COLOUR(sys_colour_AppWorkspace, 0x00f1f1f1)
+NSOPTION_COLOUR(sys_colour_Background, 0x006e6e6e)
+NSOPTION_COLOUR(sys_colour_ButtonFace, 0x00f9f9f9)
+NSOPTION_COLOUR(sys_colour_ButtonHighlight, 0x00ffffff)
+NSOPTION_COLOUR(sys_colour_ButtonShadow, 0x00aeaeae)
+NSOPTION_COLOUR(sys_colour_ButtonText, 0x004c4c4c)
+NSOPTION_COLOUR(sys_colour_CaptionText, 0x004c4c4c)
+NSOPTION_COLOUR(sys_colour_GrayText, 0x00505050)
+NSOPTION_COLOUR(sys_colour_Highlight, 0x00c00800)
+NSOPTION_COLOUR(sys_colour_HighlightText, 0x00ffffff)
+NSOPTION_COLOUR(sys_colour_InactiveBorder, 0x00f1f1f1)
+NSOPTION_COLOUR(sys_colour_InactiveCaption, 0x00e6e6e6)
+NSOPTION_COLOUR(sys_colour_InactiveCaptionText, 0x00a6a6a6)
+NSOPTION_COLOUR(sys_colour_InfoBackground, 0x008fdfef)
+NSOPTION_COLOUR(sys_colour_InfoText, 0x00000000)
+NSOPTION_COLOUR(sys_colour_Menu, 0x00f1f1f1)
+NSOPTION_COLOUR(sys_colour_MenuText, 0x004e4e4e)
+NSOPTION_COLOUR(sys_colour_Scrollbar, 0x00cccccc)
+NSOPTION_COLOUR(sys_colour_ThreeDDarkShadow, 0x00aeaeae)
+NSOPTION_COLOUR(sys_colour_ThreeDFace, 0x00f9f9f9)
+NSOPTION_COLOUR(sys_colour_ThreeDHighlight, 0x00ffffff)
+NSOPTION_COLOUR(sys_colour_ThreeDLightShadow, 0x00ffffff)
+NSOPTION_COLOUR(sys_colour_ThreeDShadow, 0x00d5d5d5)
+NSOPTION_COLOUR(sys_colour_Window, 0x00f1f1f1)
+NSOPTION_COLOUR(sys_colour_WindowFrame, 0x004e4e4e)
+NSOPTION_COLOUR(sys_colour_WindowText, 0x00000000)
diff --git a/desktop/options_main.h b/desktop/options_main.h
deleted file mode 100644
index 7b9e731..0000000
--- a/desktop/options_main.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright 2004 James Bursa <bursa at users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Option available on all platforms
- *
- * Non-platform specific options can be added by editing this file 
- *
- * Platform specific options should be added in the platform options.h.
- *
- * The following types of options are supported:
- *  - bool (OPTION_BOOL) boolean
- *  - int (OPTION_INTEGER) integer
- *  - colour (OPTION_COLOUR) colour
- *  - char* (OPTION_STRING) must be allocated on heap, may be NULL
- */
-
-#ifndef _NETSURF_DESKTOP_OPTIONS_MAIN_H_
-#define _NETSURF_DESKTOP_OPTIONS_MAIN_H_
-
-#define NSOPTION_MAIN_DEFINE			\
-	/** An HTTP proxy should be used. */	\
-	bool http_proxy;			\
-	/** Hostname of proxy. */		\
-	char *http_proxy_host;			\
-	/** Proxy port. */			\
-	int http_proxy_port;			\
-	/** Proxy authentication method. */	\
-	int http_proxy_auth;			\
-	/** Proxy authentication user name */	\
-	char *http_proxy_auth_user;		\
-	/** Proxy authentication password */	\
-	char *http_proxy_auth_pass;		\
-	/** Default font size / 0.1pt. */	\
-	int font_size;				\
-	/** Minimum font size. */		\
-	int font_min_size;			\
-	/** Default sans serif font */		\
-	char *font_sans;			\
-	/** Default serif font */		\
-	char *font_serif;			\
-	/** Default monospace font */		\
-	char *font_mono;			\
-	/** Default cursive font */		\
-	char *font_cursive;			\
-	/** Default fantasy font */		\
-	char *font_fantasy;			\
-	/** Accept-Language header. */		\
-	char *accept_language;			\
-	/** Accept-Charset header. */		\
-	char *accept_charset;					\
-	/** Preferred maximum size of memory cache / bytes. */	\
-	int memory_cache_size;					\
-	/** Preferred expiry size of disc cache / bytes. */	\
-	int disc_cache_size;					\
-	/** Preferred expiry age of disc cache / days. */	\
-	int disc_cache_age;					\
-	/** Whether to block advertisements */			\
-	bool block_ads;						\
-	/** Disable website tracking, see	                \
-	 * http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */	\
-	bool do_not_track;					\
-	/** Minimum GIF animation delay */			\
-	int minimum_gif_delay;					\
-	/** Whether to send the referer HTTP header */		\
-	bool send_referer;					\
-	/** Whether to fetch foreground images */		\
-	bool foreground_images;					\
-	/** Whether to fetch background images */		\
-	bool background_images;					\
-	/** Whether to animate images */			\
-	bool animate_images;					\
-	/** Whether to execute javascript */			\
-	bool enable_javascript;					\
-	/** How many days to retain URL data for */		\
-	int expire_url;						\
-	/** Default font family */				\
-	int font_default;					\
-	/** ca-bundle location */				\
-	char *ca_bundle;					\
-	/** ca-path location */					\
-	char *ca_path;						\
-	/** Cookie file location */				\
-	char *cookie_file;					\
-	/** Cookie jar location */				\
-	char *cookie_jar;					\
-	/** Home page location */				\
-	char *homepage_url;					\
-	/** search web from url bar */				\
-	bool search_url_bar;					\
-	/** URL completion in url bar */			\
-	bool url_suggestion;					\
-	/** default web search provider */			\
-	int search_provider;					\
-	/** default x position of new windows */		\
-	int window_x;						\
-	/** default y position of new windows */		\
-	int window_y;						\
-	/** default width of new windows */			\
-	int window_width;					\
-	/** default height of new windows */			\
-	int window_height;					\
-	/** width of screen when above options were saved */	\
-	int window_screen_width;				\
-	/** height of screen when above options were saved */	\
-	int window_screen_height;				\
-	/** default size of status bar vs. h scroll bar */	\
-	int toolbar_status_width;				\
-	/** default window scale */				\
-	int scale;							\
-	/* Whether to reflow web pages while objects are fetching */	\
-	bool incremental_reflow;					\
-	/* Minimum time between HTML reflows while objects are fetching */ \
-	unsigned int min_reflow_period; /* time in cs */		\
-	bool core_select_menu;						\
-	/** top margin of exported page */				\
-	int margin_top;							\
-	/** bottom margin of exported page */				\
-	int margin_bottom;						\
-	/** left margin of exported page */				\
-	int margin_left;						\
-	/** right margin of exported page*/				\
-	int margin_right;						\
-	/** scale of exported content*/					\
-	int export_scale;						\
-	/** suppressing images in printed content*/			\
-	bool suppress_images;						\
-	/** turning off all backgrounds for printed content*/		\
-	bool remove_backgrounds;					\
-	/** turning on content loosening for printed content*/		\
-	bool enable_loosening;						\
-	/** compression of PDF documents*/				\
-	bool enable_PDF_compression;					\
-	/** setting a password and encoding PDF documents*/		\
-	bool enable_PDF_password;					\
-									\
-	/* Fetcher configuration */					\
-	/** Maximum simultaneous active fetchers */			\
-	int max_fetchers;						\
-	/** Maximum simultaneous active fetchers per host.		\
-	 * (<=option_max_fetchers else it makes no sense) Note that	\
-	 * rfc2616 section 8.1.4 says that there should be no more	\
-	 * than two keepalive connections per host. None of the main	\
-	 * browsers follow this as it slows page fetches down		\
-	 * considerably.  See						\
-	 * https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4	\
-	 */								\
-	int max_fetchers_per_host;					\
-	/** Maximum number of inactive fetchers cached.  The total	\
-	 * number of handles netsurf will therefore have open is this	\
-	 * plus option_max_fetchers.					\
-	 */								\
-	int max_cached_fetch_handles;					\
-	/** Suppress debug output from cURL. */				\
-	bool suppress_curl_debug;					\
-									\
-	/** Whether to allow target="_blank" */				\
-	bool target_blank;						\
-									\
-	/** Whether second mouse button opens in new tab */		\
-	bool button_2_tab;						\
-									\
-	/* system colours */						\
-	colour sys_colour_ActiveBorder;					\
-	colour sys_colour_ActiveCaption;				\
-	colour sys_colour_AppWorkspace;					\
-	colour sys_colour_Background;					\
-	colour sys_colour_ButtonFace;					\
-	colour sys_colour_ButtonHighlight;				\
-	colour sys_colour_ButtonShadow;					\
-	colour sys_colour_ButtonText;					\
-	colour sys_colour_CaptionText;					\
-	colour sys_colour_GrayText;					\
-	colour sys_colour_Highlight;					\
-	colour sys_colour_HighlightText;				\
-	colour sys_colour_InactiveBorder;				\
-	colour sys_colour_InactiveCaption;				\
-	colour sys_colour_InactiveCaptionText;				\
-	colour sys_colour_InfoBackground;				\
-	colour sys_colour_InfoText;					\
-	colour sys_colour_Menu;						\
-	colour sys_colour_MenuText;					\
-	colour sys_colour_Scrollbar;					\
-	colour sys_colour_ThreeDDarkShadow;				\
-	colour sys_colour_ThreeDFace;					\
-	colour sys_colour_ThreeDHighlight;				\
-	colour sys_colour_ThreeDLightShadow;				\
-	colour sys_colour_ThreeDShadow;					\
-	colour sys_colour_Window;					\
-	colour sys_colour_WindowFrame;					\
-	colour sys_colour_WindowText
-
-#define NSOPTION_MAIN_DEFAULTS				\
-	.http_proxy = false,				\
-	.http_proxy_host = NULL,			\
-	.http_proxy_port = 8080,			\
-	.http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE,	\
-	.http_proxy_auth_user = NULL,			\
-	.http_proxy_auth_pass = NULL,			\
-	.font_size = 128,				\
-	.font_min_size = 85,				\
-	.font_sans = NULL,				\
-	.font_serif = NULL,				\
-	.font_mono = NULL,				\
-	.font_cursive = NULL,				\
-	.font_fantasy = NULL,				\
-	.accept_language = NULL,			\
-	.accept_charset = NULL,				\
-	.memory_cache_size = 12 * 1024 * 1024,		\
-	.disc_cache_size = 1024 * 1024 * 1024,		\
-	.disc_cache_age = 28,				\
-	.block_ads = false,				\
-	.do_not_track = false,				\
-	.minimum_gif_delay = 10,			\
-	.send_referer = true,				\
-	.foreground_images = true,			\
-	.background_images = true,			\
-	.animate_images = true,				\
-	.expire_url = 28,				\
-	.font_default = PLOT_FONT_FAMILY_SANS_SERIF,	\
-	.ca_bundle = NULL,				\
-	.ca_path = NULL,				\
-	.cookie_file = NULL,				\
-	.cookie_jar = NULL,				\
-	.homepage_url = NULL,				\
-	.search_url_bar = false,			\
-	.url_suggestion = true,				\
-	.search_provider = 0,				\
-	.window_x = 0,					\
-	.window_y = 0,					\
-	.window_width = 0,				\
-	.window_height = 0,				\
-	.window_screen_width = 0,			\
-	.window_screen_height = 0,			\
-	.toolbar_status_width = 6667,			\
-	.scale = 100,					\
-	.incremental_reflow = true,			\
-	.min_reflow_period = DEFAULT_REFLOW_PERIOD,	\
-	.core_select_menu = false,			\
-	.margin_top = DEFAULT_MARGIN_TOP_MM,		\
-	.margin_bottom = DEFAULT_MARGIN_BOTTOM_MM,	\
-	.margin_left = DEFAULT_MARGIN_LEFT_MM,		\
-	.margin_right = DEFAULT_MARGIN_RIGHT_MM,	\
-	.export_scale = DEFAULT_EXPORT_SCALE * 100,	\
-	.suppress_images = false,			\
-	.remove_backgrounds = false,			\
-	.enable_loosening = true,			\
-	.enable_PDF_compression = true,			\
-	.enable_PDF_password = false,			\
-	.max_fetchers = 24,				\
-	.max_fetchers_per_host = 5,			\
-	.max_cached_fetch_handles = 6,			\
-	.suppress_curl_debug = true,			\
-	.target_blank = true,				\
-	.button_2_tab = true,				\
-	.enable_javascript = true
-
-#define NSOPTION_MAIN_SYS_COLOUR_DEFAULTS		\
-	.sys_colour_ActiveBorder = 0x00000000,		\
-	.sys_colour_ActiveCaption = 0x00000000,		\
-	.sys_colour_AppWorkspace = 0x00000000,		\
-	.sys_colour_Background = 0x00000000,		\
-	.sys_colour_ButtonFace = 0x00000000,		\
-	.sys_colour_ButtonHighlight = 0x00000000,	\
-	.sys_colour_ButtonShadow = 0x00000000,		\
-	.sys_colour_ButtonText = 0x00000000,		\
-	.sys_colour_CaptionText = 0x0000000,		\
-	.sys_colour_GrayText = 0x00000000,		\
-	.sys_colour_Highlight = 0x00000000,		\
-	.sys_colour_HighlightText = 0x00000000,		\
-	.sys_colour_InactiveBorder = 0x00000000,	\
-	.sys_colour_InactiveCaption = 0x00000000,	\
-	.sys_colour_InactiveCaptionText = 0x00000000,	\
-	.sys_colour_InfoBackground = 0x00000000,	\
-	.sys_colour_InfoText = 0x00000000,		\
-	.sys_colour_Menu = 0x00000000,			\
-	.sys_colour_MenuText = 0x0000000,		\
-	.sys_colour_Scrollbar = 0x0000000,		\
-	.sys_colour_ThreeDDarkShadow = 0x000000,	\
-	.sys_colour_ThreeDFace = 0x000000,		\
-	.sys_colour_ThreeDHighlight = 0x000000,		\
-	.sys_colour_ThreeDLightShadow = 0x000000,	\
-	.sys_colour_ThreeDShadow = 0x000000,		\
-	.sys_colour_Window = 0x000000,			\
-	.sys_colour_WindowFrame = 0x000000,		\
-	.sys_colour_WindowText = 0x000000
-
-
-#define NSOPTION_MAIN_TABLE						\
-	{ "http_proxy",		OPTION_BOOL,	&nsoptions.http_proxy }, \
-	{ "http_proxy_host",	OPTION_STRING,	&nsoptions.http_proxy_host }, \
-	{ "http_proxy_port",	OPTION_INTEGER,	&nsoptions.http_proxy_port }, \
-	{ "http_proxy_auth",	OPTION_INTEGER,	&nsoptions.http_proxy_auth }, \
-	{ "http_proxy_auth_user", OPTION_STRING, &nsoptions.http_proxy_auth_user }, \
-	{ "http_proxy_auth_pass", OPTION_STRING, &nsoptions.http_proxy_auth_pass }, \
-	{ "font_size",		OPTION_INTEGER,	&nsoptions.font_size },	\
-	{ "font_min_size",	OPTION_INTEGER,	&nsoptions.font_min_size }, \
-	{ "font_sans",		OPTION_STRING,	&nsoptions.font_sans },	\
-	{ "font_serif",		OPTION_STRING,	&nsoptions.font_serif }, \
-	{ "font_mono",		OPTION_STRING,	&nsoptions.font_mono },	\
-	{ "font_cursive",	OPTION_STRING,	&nsoptions.font_cursive }, \
-	{ "font_fantasy",	OPTION_STRING,	&nsoptions.font_fantasy }, \
-	{ "accept_language",	OPTION_STRING,	&nsoptions.accept_language }, \
-	{ "accept_charset",	OPTION_STRING,	&nsoptions.accept_charset }, \
-	{ "memory_cache_size",	OPTION_INTEGER,	&nsoptions.memory_cache_size },	\
-	{ "disc_cache_size",	OPTION_INTEGER,	&nsoptions.disc_cache_size },	\
-	{ "disc_cache_age",	OPTION_INTEGER,	&nsoptions.disc_cache_age }, \
-	{ "block_advertisements", OPTION_BOOL,	&nsoptions.block_ads },	\
-	{ "do_not_track", OPTION_BOOL,	&nsoptions.do_not_track },	\
-	{ "minimum_gif_delay",	OPTION_INTEGER,	&nsoptions.minimum_gif_delay },	\
-	{ "send_referer",	OPTION_BOOL,	&nsoptions.send_referer }, \
-	{ "foreground_images",	OPTION_BOOL,	&nsoptions.foreground_images },	\
-	{ "background_images",	OPTION_BOOL,	&nsoptions.background_images },	\
-	{ "animate_images",	OPTION_BOOL,	&nsoptions.animate_images }, \
-	{ "enable_javascript",	OPTION_BOOL,	&nsoptions.enable_javascript},	\
-	{ "expire_url",		OPTION_INTEGER,	&nsoptions.expire_url }, \
-	{ "font_default",	OPTION_INTEGER,	&nsoptions.font_default }, \
-	{ "ca_bundle",		OPTION_STRING,	&nsoptions.ca_bundle },	\
-	{ "ca_path",		OPTION_STRING,	&nsoptions.ca_path },	\
-	{ "cookie_file",	OPTION_STRING,	&nsoptions.cookie_file }, \
-	{ "cookie_jar",		OPTION_STRING,	&nsoptions.cookie_jar }, \
-	{ "homepage_url",	OPTION_STRING,	&nsoptions.homepage_url }, \
-	{ "search_url_bar",	OPTION_BOOL,	&nsoptions.search_url_bar}, \
-	{ "search_provider",	OPTION_INTEGER,	&nsoptions.search_provider}, \
-	{ "url_suggestion",	OPTION_BOOL,	&nsoptions.url_suggestion }, \
-	{ "window_x",		OPTION_INTEGER,	&nsoptions.window_x },	\
-	{ "window_y",		OPTION_INTEGER,	&nsoptions.window_y },	\
-	{ "window_width",	OPTION_INTEGER,	&nsoptions.window_width }, \
-	{ "window_height",	OPTION_INTEGER,	&nsoptions.window_height }, \
-	{ "window_screen_width", OPTION_INTEGER, &nsoptions.window_screen_width }, \
-	{ "window_screen_height", OPTION_INTEGER, &nsoptions.window_screen_height }, \
-	{ "toolbar_status_size", OPTION_INTEGER, &nsoptions.toolbar_status_width }, \
-	{ "scale",		OPTION_INTEGER,	&nsoptions.scale },	\
-	{ "incremental_reflow",	OPTION_BOOL,	&nsoptions.incremental_reflow }, \
-	{ "min_reflow_period",	OPTION_INTEGER,	&nsoptions.min_reflow_period },	\
- 	{ "core_select_menu",	OPTION_BOOL,	&nsoptions.core_select_menu }, \
-		/* Fetcher options */					\
-	{ "max_fetchers",	OPTION_INTEGER,	&nsoptions.max_fetchers }, \
-	{ "max_fetchers_per_host", OPTION_INTEGER, &nsoptions.max_fetchers_per_host }, \
-	{ "max_cached_fetch_handles", OPTION_INTEGER, &nsoptions.max_cached_fetch_handles }, \
-	{ "suppress_curl_debug",OPTION_BOOL,	&nsoptions.suppress_curl_debug }, \
-	{ "target_blank",	OPTION_BOOL,	&nsoptions.target_blank }, \
-	{ "button_2_tab",	OPTION_BOOL,	&nsoptions.button_2_tab }, \
-		/* PDF / Print options*/				\
-	{ "margin_top",		OPTION_INTEGER,	&nsoptions.margin_top},	\
-	{ "margin_bottom",	OPTION_INTEGER,	&nsoptions.margin_bottom}, \
-	{ "margin_left",	OPTION_INTEGER,	&nsoptions.margin_left}, \
-	{ "margin_right",	OPTION_INTEGER,	&nsoptions.margin_right}, \
- 	{ "export_scale",	OPTION_INTEGER,	&nsoptions.export_scale}, \
-	{ "suppress_images",	OPTION_BOOL,	&nsoptions.suppress_images}, \
-	{ "remove_backgrounds",	OPTION_BOOL,	&nsoptions.remove_backgrounds},	\
-	{ "enable_loosening",	OPTION_BOOL,	&nsoptions.enable_loosening}, \
- 	{ "enable_PDF_compression", OPTION_BOOL, &nsoptions.enable_PDF_compression}, \
- 	{ "enable_PDF_password", OPTION_BOOL,	&nsoptions.enable_PDF_password}, \
-									\
-		/* System colours */					\
-	{ "sys_colour_ActiveBorder",OPTION_COLOUR,&nsoptions.sys_colour_ActiveBorder },	\
-	{ "sys_colour_ActiveCaption",OPTION_COLOUR,&nsoptions.sys_colour_ActiveCaption }, \
-	{ "sys_colour_AppWorkspace",OPTION_COLOUR,&nsoptions.sys_colour_AppWorkspace },	\
-	{ "sys_colour_Background",OPTION_COLOUR,&nsoptions.sys_colour_Background }, \
-	{ "sys_colour_ButtonFace",OPTION_COLOUR,&nsoptions.sys_colour_ButtonFace }, \
-	{ "sys_colour_ButtonHighlight",OPTION_COLOUR,&nsoptions.sys_colour_ButtonHighlight }, \
-	{ "sys_colour_ButtonShadow",OPTION_COLOUR,&nsoptions.sys_colour_ButtonShadow },	\
-	{ "sys_colour_ButtonText",OPTION_COLOUR,&nsoptions.sys_colour_ButtonText }, \
-	{ "sys_colour_CaptionText",OPTION_COLOUR,&nsoptions.sys_colour_CaptionText }, \
-	{ "sys_colour_GrayText",OPTION_COLOUR,&nsoptions.sys_colour_GrayText },	\
-	{ "sys_colour_Highlight",OPTION_COLOUR,&nsoptions.sys_colour_Highlight }, \
-	{ "sys_colour_HighlightText",OPTION_COLOUR,&nsoptions.sys_colour_HighlightText }, \
-	{ "sys_colour_InactiveBorder",OPTION_COLOUR,&nsoptions.sys_colour_InactiveBorder }, \
-	{ "sys_colour_InactiveCaption",OPTION_COLOUR,&nsoptions.sys_colour_InactiveCaption }, \
-	{ "sys_colour_InactiveCaptionText",OPTION_COLOUR,&nsoptions.sys_colour_InactiveCaptionText }, \
-	{ "sys_colour_InfoBackground",OPTION_COLOUR,&nsoptions.sys_colour_InfoBackground }, \
-	{ "sys_colour_InfoText",OPTION_COLOUR,&nsoptions.sys_colour_InfoText },	\
-	{ "sys_colour_Menu",OPTION_COLOUR,&nsoptions.sys_colour_Menu },	\
-	{ "sys_colour_MenuText",OPTION_COLOUR,&nsoptions.sys_colour_MenuText },	\
-	{ "sys_colour_Scrollbar",OPTION_COLOUR,&nsoptions.sys_colour_Scrollbar }, \
-	{ "sys_colour_ThreeDDarkShadow",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDDarkShadow },	\
-	{ "sys_colour_ThreeDFace",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDFace }, \
-	{ "sys_colour_ThreeDHighlight",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDHighlight }, \
-	{ "sys_colour_ThreeDLightShadow", OPTION_COLOUR,&nsoptions.sys_colour_ThreeDLightShadow }, \
-	{ "sys_colour_ThreeDShadow", OPTION_COLOUR,&nsoptions.sys_colour_ThreeDShadow },	\
-	{ "sys_colour_Window", OPTION_COLOUR,&nsoptions.sys_colour_Window }, \
-	{ "sys_colour_WindowFrame", OPTION_COLOUR,&nsoptions.sys_colour_WindowFrame }, \
-	{ "sys_colour_WindowText", OPTION_COLOUR,&nsoptions.sys_colour_WindowText }
-
-#endif
diff --git a/desktop/print.c b/desktop/print.c
index e1cd48f..8f83f2d 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -30,7 +30,7 @@
 #include "content/content.h"
 #include "content/hlcache.h"
 #include "css/utils.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/print.h"
 #include "desktop/printer.h"
 #include "render/box.h"
diff --git a/desktop/save_pdf/font_haru.c b/desktop/save_pdf/font_haru.c
index c907531..57d36fe 100644
--- a/desktop/save_pdf/font_haru.c
+++ b/desktop/save_pdf/font_haru.c
@@ -39,7 +39,7 @@
 #include "css/css.h"
 #include "css/utils.h"
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_pdf/font_haru.h"
 #include "render/font.h"
 #include "utils/log.h"
diff --git a/desktop/save_pdf/pdf_plotters.c b/desktop/save_pdf/pdf_plotters.c
index 847d6da..123408d 100644
--- a/desktop/save_pdf/pdf_plotters.c
+++ b/desktop/save_pdf/pdf_plotters.c
@@ -31,7 +31,7 @@
 #include <hpdf.h>
 
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/print.h"
 #include "desktop/printer.h"
diff --git a/desktop/scrollbar.c b/desktop/scrollbar.c
index 5517a6f..d24ea72 100644
--- a/desktop/scrollbar.c
+++ b/desktop/scrollbar.c
@@ -27,7 +27,7 @@
 
 #include "desktop/mouse.h"
 #include "desktop/scrollbar.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/plot_style.h"
 #include "utils/log.h"
diff --git a/desktop/search.c b/desktop/search.c
index 014488e..3a7c768 100644
--- a/desktop/search.c
+++ b/desktop/search.c
@@ -30,7 +30,7 @@
 #include "content/hlcache.h"
 #include "desktop/browser_private.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/search.h"
 #include "desktop/selection.h"
 #include "render/box.h"
diff --git a/desktop/searchweb.c b/desktop/searchweb.c
index a90627a..87e3e21 100644
--- a/desktop/searchweb.c
+++ b/desktop/searchweb.c
@@ -27,7 +27,7 @@
 #include "content/hlcache.h"
 #include "desktop/browser.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/searchweb.h"
 #include "utils/config.h"
 #include "utils/log.h"
diff --git a/desktop/system_colour.c b/desktop/system_colour.c
new file mode 100644
index 0000000..4ef1709
--- /dev/null
+++ b/desktop/system_colour.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * System colour handling
+ *
+ */
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "css/utils.h"
+#include "desktop/gui.h"
+#include "utils/nsoption.h"
+
+
+
+#define colour_list_len ((NSOPTION_SYS_COLOUR_END - NSOPTION_SYS_COLOUR_START) + 1)
+
+static lwc_string *colour_list[colour_list_len];
+
+static lwc_string **gui_system_colour_pw = NULL;
+
+
+bool gui_system_colour_init(void)
+{
+	unsigned int ccount;
+
+	if (gui_system_colour_pw != NULL) 
+		return false;
+
+	/* Intern colour strings */
+	for (ccount = 0; ccount < colour_list_len; ccount++) {
+		struct nsoption_s *opt;
+		opt = &nsoptions[ccount + NSOPTION_SYS_COLOUR_START];
+		if (lwc_intern_string(opt->key + SLEN("sys_colour_"), 
+				      opt->key_len - SLEN("sys_colour_"), 
+				      &(colour_list[ccount])) != lwc_error_ok) {
+			return false;
+		}
+	}
+
+	gui_system_colour_pw = colour_list;
+	
+	return true;
+}
+
+void gui_system_colour_finalize(void)
+{
+	unsigned int ccount;
+
+	for (ccount = 0; ccount < colour_list_len; ccount++) {
+		lwc_string_unref(colour_list[ccount]);
+	}
+}
+
+colour gui_system_colour_char(const char *name)
+{
+	colour ret = 0;
+	unsigned int ccount;
+
+	for (ccount = 0; ccount < colour_list_len; ccount++) {
+		if (strcmp(name,
+			   nsoptions[ccount + NSOPTION_SYS_COLOUR_START].key + SLEN("sys_colour_")) == 0) {
+			ret = nsoptions[ccount + NSOPTION_SYS_COLOUR_START].value.c;
+			break;
+		}
+	}
+	return ret;
+}
+
+css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
+{
+	unsigned int ccount;
+	bool match;
+
+	for (ccount = 0; ccount < colour_list_len; ccount++) {
+		if (lwc_string_caseless_isequal(name, 
+				colour_list[ccount],
+				&match) == lwc_error_ok && match) {
+			*colour = ns_color_to_nscss(nsoptions[ccount + NSOPTION_SYS_COLOUR_START].value.c);
+			return CSS_OK;
+		}
+	}	
+
+	return CSS_INVALID;
+}
diff --git a/desktop/thumbnail.c b/desktop/thumbnail.c
index 975e799..1011adc 100644
--- a/desktop/thumbnail.c
+++ b/desktop/thumbnail.c
@@ -27,7 +27,7 @@
 #include "content/hlcache.h"
 #include "desktop/browser.h"
 #include "desktop/knockout.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/thumbnail.h"
 #include "utils/log.h"
diff --git a/desktop/tree.c b/desktop/tree.c
index e12da8b..93d6a63 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -34,7 +34,7 @@
 #include "desktop/textarea.h"
 #include "desktop/textinput.h"
 #include "desktop/tree.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "render/font.h"
 #include "utils/log.h"
@@ -1556,9 +1556,9 @@ const char *tree_node_element_get_text(struct node_element *element)
  *
  * \return  the node element's icon
  */
-struct bitmap *tree_node_element_get_icon(struct node_element *element)
+struct bitmap *tree_node_get_icon(struct node *node)
 {
-	return element->bitmap;
+	return node->data.bitmap;
 }
 
 
diff --git a/desktop/tree.h b/desktop/tree.h
index 20ade30..87b0216 100644
--- a/desktop/tree.h
+++ b/desktop/tree.h
@@ -200,7 +200,7 @@ void tree_update_node_element(struct tree *tree, struct node_element *element,
 		const char *text, void *bitmap);
 bool tree_update_element_text(struct tree *tree, struct node_element *element, char *text);
 const char *tree_node_element_get_text(struct node_element *element);
-struct bitmap *tree_node_element_get_icon(struct node_element *element);
+struct bitmap *tree_node_get_icon(struct node *node);
 struct node *tree_get_root(struct tree *tree);
 bool tree_is_edited(struct tree *tree);
 tree_drag_type tree_drag_status(struct tree *tree);
diff --git a/desktop/tree_url_node.c b/desktop/tree_url_node.c
index 541636f..099be81 100644
--- a/desktop/tree_url_node.c
+++ b/desktop/tree_url_node.c
@@ -32,7 +32,7 @@
 #include "content/hlcache.h"
 #include "content/urldb.h"
 #include "desktop/browser.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/tree_url_node.h"
 #include "utils/corestrings.h"
 #include "utils/libdom.h"
@@ -342,11 +342,7 @@ const char *tree_url_node_get_url(struct node *node)
 
 struct bitmap *tree_url_node_get_icon(struct node *node)
 {
-	struct node_element *element;
-	element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
-	if (element == NULL)
-		return NULL;
-	return tree_node_element_get_icon(element);
+	return tree_node_get_icon(node);
 }
 
 
diff --git a/framebuffer/Makefile.target b/framebuffer/Makefile.target
index 1441710..bad31ed 100644
--- a/framebuffer/Makefile.target
+++ b/framebuffer/Makefile.target
@@ -138,7 +138,7 @@ $(eval $(foreach V,$(filter FB_IMAGE_%,$(.VARIABLES)),$(call convert_image,$($(V
 # S_FRAMEBUFFER are sources purely for the framebuffer build
 S_FRAMEBUFFER := gui.c framebuffer.c tree.c schedule.c			\
 	thumbnail.c misc.c bitmap.c filetype.c login.c findfile.c	\
-	localhistory.c system_colour.c clipboard.c
+	localhistory.c clipboard.c
 
 S_FRAMEBUFFER_FBTK := fbtk.c event.c fill.c bitmap.c user.c window.c 	\
 	text.c scroll.c osk.c 
diff --git a/framebuffer/font_freetype.c b/framebuffer/font_freetype.c
index 987b101..87751a3 100644
--- a/framebuffer/font_freetype.c
+++ b/framebuffer/font_freetype.c
@@ -29,7 +29,7 @@
 #include "utils/filepath.h"
 #include "utils/utf8.h"
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 #include "framebuffer/gui.h"
 #include "framebuffer/font.h"
diff --git a/framebuffer/font_internal.c b/framebuffer/font_internal.c
index ff2bfa1..60f1b8e 100644
--- a/framebuffer/font_internal.c
+++ b/framebuffer/font_internal.c
@@ -23,7 +23,7 @@
 #include <assert.h>
 #include "css/css.h"
 #include "render/font.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/utf8.h"
 
 #include "framebuffer/gui.h"
diff --git a/framebuffer/gui.c b/framebuffer/gui.c
index 3ceb814..d9e78d7 100644
--- a/framebuffer/gui.c
+++ b/framebuffer/gui.c
@@ -36,7 +36,7 @@
 #include "desktop/mouse.h"
 #include "desktop/plotters.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/filepath.h"
 #include "utils/log.h"
 #include "utils/messages.h"
@@ -476,44 +476,67 @@ process_cmdline(int argc, char** argv)
 	return true;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for framebuffer frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
 	/* Set defaults for absent option strings */
 	nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
 	nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
 
 	if (nsoption_charp(cookie_file) == NULL ||
-			nsoption_charp(cookie_jar == NULL)) {
-		die("Failed initialising cookie options");
+	    nsoption_charp(cookie_jar) == NULL) {
+		LOG(("Failed initialising cookie options"));
+		return NSERROR_BAD_PARAMETER;
 	}
-}
-
-static void
-gui_init(int argc, char** argv)
-{
-	nsfb_t *nsfb;
-
-	/* Override, since we have no support for non-core SELECT menu */
-	nsoption_set_bool(core_select_menu, true);
-
-	if (process_cmdline(argc,argv) != true)
-		die("unable to process command line.\n");
-
-	nsfb = framebuffer_initialise(fename, fewidth, feheight, febpp);
-	if (nsfb == NULL)
-		die("Unable to initialise framebuffer");
 
-	framebuffer_set_cursor(&pointer_image);
+	/* set system colours for framebuffer ui */
+	nsoption_set_colour(sys_colour_ActiveBorder, 0x00000000);
+	nsoption_set_colour(sys_colour_ActiveCaption, 0x00ddddcc);
+	nsoption_set_colour(sys_colour_AppWorkspace, 0x00eeeeee);
+	nsoption_set_colour(sys_colour_Background, 0x00aa0000);
+	nsoption_set_colour(sys_colour_ButtonFace, 0x00dddddd);
+	nsoption_set_colour(sys_colour_ButtonHighlight, 0x00cccccc);
+	nsoption_set_colour(sys_colour_ButtonShadow, 0x00bbbbbb);
+	nsoption_set_colour(sys_colour_ButtonText, 0x00000000);
+	nsoption_set_colour(sys_colour_CaptionText, 0x00000000);
+	nsoption_set_colour(sys_colour_GrayText, 0x00777777);
+	nsoption_set_colour(sys_colour_Highlight, 0x00ee0000);
+	nsoption_set_colour(sys_colour_HighlightText, 0x00000000);
+	nsoption_set_colour(sys_colour_InactiveBorder, 0x00000000);
+	nsoption_set_colour(sys_colour_InactiveCaption, 0x00ffffff);
+	nsoption_set_colour(sys_colour_InactiveCaptionText, 0x00cccccc);
+	nsoption_set_colour(sys_colour_InfoBackground, 0x00aaaaaa);
+	nsoption_set_colour(sys_colour_InfoText, 0x00000000);
+	nsoption_set_colour(sys_colour_Menu, 0x00aaaaaa);
+	nsoption_set_colour(sys_colour_MenuText, 0x00000000);
+	nsoption_set_colour(sys_colour_Scrollbar, 0x00aaaaaa);
+	nsoption_set_colour(sys_colour_ThreeDDarkShadow, 0x00555555);
+	nsoption_set_colour(sys_colour_ThreeDFace, 0x00dddddd);
+	nsoption_set_colour(sys_colour_ThreeDHighlight, 0x00aaaaaa);
+	nsoption_set_colour(sys_colour_ThreeDLightShadow, 0x00999999);
+	nsoption_set_colour(sys_colour_ThreeDShadow, 0x00777777);
+	nsoption_set_colour(sys_colour_Window, 0x00aaaaaa);
+	nsoption_set_colour(sys_colour_WindowFrame, 0x00000000);
+	nsoption_set_colour(sys_colour_WindowText, 0x00000000);
 
-	if (fb_font_init() == false)
-		die("Unable to initialise the font system");
+	return NSERROR_OK;
+}
 
-	fbtk = fbtk_init(nsfb);
 
-	fbtk_enable_oskb(fbtk);
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+        /* set log stream to be non-buffering */
+	setbuf(fptr, NULL);
 
-	urldb_load_cookies(nsoption_charp(cookie_file));
+	return true;
 }
 
 /** Entry point from OS.
@@ -529,29 +552,62 @@ main(int argc, char** argv)
 	char *options;
 	char *messages;
 	nsurl *url;
-	nserror error;
-
-	setbuf(stderr, NULL);
+	nserror ret;
+	nsfb_t *nsfb;
 
 	respaths = fb_init_resource(NETSURF_FB_RESPATH":"NETSURF_FB_FONTPATH);
 
-	options = filepath_find(respaths, "Choices");
-	messages = filepath_find(respaths, "messages");
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(nslog_stream_configure, &argc, argv);
 
-	netsurf_init(&argc, &argv, options, messages);
+	/* user options setup */
+	ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	options = filepath_find(respaths, "Choices");
+	nsoption_read(options, nsoptions);
+	free(options);
+	nsoption_commandline(&argc, argv, nsoptions);
 
+	/* common initialisation */
+	messages = filepath_find(respaths, "Messages");
+	ret = netsurf_init(messages);
 	free(messages);
-	free(options);
+	if (ret != NSERROR_OK) {
+		die("NetSurf failed to initialise");
+	}
 
-	gui_init(argc, argv);
+	/* Override, since we have no support for non-core SELECT menu */
+	nsoption_set_bool(core_select_menu, true);
+
+	if (process_cmdline(argc,argv) != true)
+		die("unable to process command line.\n");
+
+	nsfb = framebuffer_initialise(fename, fewidth, feheight, febpp);
+	if (nsfb == NULL)
+		die("Unable to initialise framebuffer");
+
+	framebuffer_set_cursor(&pointer_image);
+
+	if (fb_font_init() == false)
+		die("Unable to initialise the font system");
+
+	fbtk = fbtk_init(nsfb);
+
+	fbtk_enable_oskb(fbtk);
+
+	urldb_load_cookies(nsoption_charp(cookie_file));
 
 	/* create an initial browser window */
 
 	LOG(("calling browser_window_create"));
 
-	error = nsurl_create(feurl, &url);
-	if (error == NSERROR_OK) {
-		error = browser_window_create(BROWSER_WINDOW_VERIFIABLE |
+	ret = nsurl_create(feurl, &url);
+	if (ret == NSERROR_OK) {
+		ret = browser_window_create(BROWSER_WINDOW_VERIFIABLE |
 					      BROWSER_WINDOW_HISTORY,
 					      url,
 					      NULL,
@@ -559,8 +615,8 @@ main(int argc, char** argv)
 					      &bw);
 		nsurl_unref(url);
 	}
-	if (error != NSERROR_OK) {
-		warn_user(messages_get_errorcode(error), 0);
+	if (ret != NSERROR_OK) {
+		warn_user(messages_get_errorcode(ret), 0);
 	} else {
 		netsurf_main_loop();
 
@@ -569,6 +625,9 @@ main(int argc, char** argv)
 
 	netsurf_exit();
 
+	/* finalise options */
+	nsoption_finalise(nsoptions, nsoptions_default);
+
 	return 0;
 }
 
@@ -1401,7 +1460,7 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width)
 
 	gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
 
-	statusbar_width = nsoption_int(toolbar_status_width) *
+	statusbar_width = nsoption_int(toolbar_status_size) *
 		fbtk_get_width(gw->window) / 10000;
 
 	/* toolbar */
diff --git a/framebuffer/localhistory.c b/framebuffer/localhistory.c
index f6c24a1..e23dd1f 100644
--- a/framebuffer/localhistory.c
+++ b/framebuffer/localhistory.c
@@ -35,7 +35,7 @@
 #include "desktop/gui.h"
 #include "desktop/plotters.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/url.h"
 #include "utils/messages.h"
diff --git a/framebuffer/options.h b/framebuffer/options.h
index 760cc3b..eee6f4b 100644
--- a/framebuffer/options.h
+++ b/framebuffer/options.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008, 2010 Daniel Silverstone <dsilvers at netsurf-browser.org>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -16,92 +16,52 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef _NETSURF_FRAMEBUFFER_OPTIONS_H_
 #define _NETSURF_FRAMEBUFFER_OPTIONS_H_
 
-#define NSOPTION_EXTRA_DEFINE						\
-	/* surface options */						\
-	int fb_depth;							\
-	int fb_refresh;							\
-	char *fb_device;						\
-	char *fb_input_devpath;						\
-	char *fb_input_glob;						\
-									\
-	/* toolkit options */						\
-	int fb_furniture_size; /**< toolkit furniture size */		\
-	int fb_toolbar_size; /**< toolbar furniture size */		\
-	char *fb_toolbar_layout; /**< toolbar layout */			\
-	bool fb_osk; /**< enable on screen keyboard */			\
-									\
-	/* font options */						\
-	bool fb_font_monochrome; /**< render font monochrome */		\
-	int fb_font_cachesize; /**< size of font glyph cache in kilobytes. */ \
-									\
-	char *fb_face_sans_serif; /**< default sans face */		\
-	char *fb_face_sans_serif_bold; /**< bold sans face */		\
-	char *fb_face_sans_serif_italic; /**< bold sans face */		\
-	char *fb_face_sans_serif_italic_bold; /**< bold sans face */	\
-									\
-	char *fb_face_serif; /**< serif face */				\
-	char *fb_face_serif_bold; /**< bold serif face */		\
-									\
-	char *fb_face_monospace; /**< monospace face */			\
-	char *fb_face_monospace_bold; /**< bold monospace face */	\
-									\
-	char *fb_face_cursive; /**< cursive face */			\
-	char *fb_face_fantasy /**< fantasy face */			
+/* currently nothing here */
 
-#define NSOPTION_EXTRA_DEFAULTS				\
-	.fb_depth = 32,					\
-	.fb_refresh = 70,				\
-	.fb_device = NULL,				\
-	.fb_input_devpath = NULL,			\
-	.fb_input_glob = NULL,				\
-	.fb_furniture_size = 18,			\
-	.fb_toolbar_size = 30,				\
-	.fb_toolbar_layout = NULL,				\
-	.fb_osk = false,				\
-	.fb_font_monochrome = false,			\
-	.fb_font_cachesize = 2048,			\
-	.fb_face_sans_serif = NULL,			\
-	.fb_face_sans_serif_bold = NULL,		\
-	.fb_face_sans_serif_italic = NULL,		\
-	.fb_face_sans_serif_italic_bold = NULL,		\
-	.fb_face_serif = NULL,				\
-	.fb_face_serif_bold = NULL,			\
-	.fb_face_monospace = NULL,			\
-	.fb_face_monospace_bold = NULL,			\
-	.fb_face_cursive = NULL,			\
-	.fb_face_fantasy = NULL			
+#endif
 
-#define NSOPTION_EXTRA_TABLE						\
-	{ "fb_depth", OPTION_INTEGER, &nsoptions.fb_depth },		\
-	{ "fb_refresh", OPTION_INTEGER, &nsoptions.fb_refresh },	\
-	{ "fb_device", OPTION_STRING, &nsoptions.fb_device },		\
-	{ "fb_input_devpath", OPTION_STRING, &nsoptions.fb_input_devpath }, \
-	{ "fb_input_glob", OPTION_STRING, &nsoptions.fb_input_glob },	\
-	{ "fb_furniture_size", OPTION_INTEGER, &nsoptions.fb_furniture_size }, \
-	{ "fb_toolbar_size", OPTION_INTEGER, &nsoptions.fb_toolbar_size }, \
-	{ "fb_toolbar_layout", OPTION_STRING, &nsoptions.fb_toolbar_layout }, \
-	{ "fb_osk", OPTION_BOOL, &nsoptions.fb_osk },			\
-	{ "fb_font_monochrome", OPTION_BOOL, &nsoptions.fb_font_monochrome }, \
-	{ "fb_font_cachesize", OPTION_INTEGER, &nsoptions.fb_font_cachesize }, \
-	{ "fb_face_sans_serif", OPTION_STRING, &nsoptions.fb_face_sans_serif }, \
-	{ "fb_face_sans_serif_bold", OPTION_STRING, &nsoptions.fb_face_sans_serif_bold }, \
-	{ "fb_face_sans_serif_italic", OPTION_STRING, &nsoptions.fb_face_sans_serif_italic }, \
-	{ "fb_face_sans_serif_italic_bold", OPTION_STRING, &nsoptions.fb_face_sans_serif_italic_bold }, \
-	{ "fb_face_serif", OPTION_STRING, &nsoptions.fb_face_serif },	\
-	{ "fb_serif_bold", OPTION_STRING, &nsoptions.fb_face_serif_bold }, \
-	{ "fb_face_monospace", OPTION_STRING, &nsoptions.fb_face_monospace }, \
-	{ "fb_face_monospace_bold", OPTION_STRING, &nsoptions.fb_face_monospace_bold }, \
-	{ "fb_face_cursive", OPTION_STRING, &nsoptions.fb_face_cursive }, \
-	{ "fb_face_fantasy", OPTION_STRING, &nsoptions.fb_face_fantasy }
+/***** surface options *****/
 
-#endif
+NSOPTION_INTEGER(fb_depth, 32)
+NSOPTION_INTEGER(fb_refresh, 70)
+NSOPTION_STRING(fb_device, NULL)
+NSOPTION_STRING(fb_input_devpath, NULL)
+NSOPTION_STRING(fb_input_glob, NULL)
+
+/***** toolkit options *****/
+
+/** toolkit furniture size */
+NSOPTION_INTEGER(fb_furniture_size, 18)
+/** toolbar furniture size */
+NSOPTION_INTEGER(fb_toolbar_size, 30)
+/** toolbar layout */
+NSOPTION_STRING(fb_toolbar_layout, NULL)
+/** enable on screen keyboard */
+NSOPTION_BOOL(fb_osk, false)
+
+/***** font options *****/
+
+/** render all fonts monochrome */
+NSOPTION_BOOL(fb_font_monochrome, false)
+/** size of font glyph cache in kilobytes. */
+NSOPTION_INTEGER(fb_font_cachesize, 2048)
+
+/* Font face paths. These are treated as absolute paths if they start
+ * with a / otherwise the compile time resource path is searched. 
+ */
+NSOPTION_STRING(fb_face_sans_serif, NULL)
+NSOPTION_STRING(fb_face_sans_serif_bold, NULL)
+NSOPTION_STRING(fb_face_sans_serif_italic, NULL)
+NSOPTION_STRING(fb_face_sans_serif_italic_bold, NULL)
+NSOPTION_STRING(fb_face_serif, NULL)
+NSOPTION_STRING(fb_face_serif_bold, NULL)
+NSOPTION_STRING(fb_face_monospace, NULL)
+NSOPTION_STRING(fb_face_monospace_bold, NULL)
+NSOPTION_STRING(fb_face_cursive, NULL)
+NSOPTION_STRING(fb_face_fantasy, NULL)
 
 /*
  * Local Variables:
diff --git a/framebuffer/system_colour.c b/framebuffer/system_colour.c
deleted file mode 100644
index 18b25ee..0000000
--- a/framebuffer/system_colour.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = {
-	{
-		"ActiveBorder",
-		SLEN("ActiveBorder"),
-		0xff000000,
-		&nsoption_colour(sys_colour_ActiveBorder),
-		NULL
-	}, {
-		"ActiveCaption",
-		SLEN("ActiveCaption"),
-		0xffddddcc,
-		&nsoption_colour(sys_colour_ActiveCaption),
-		NULL
-	}, {
-		"AppWorkspace",
-		SLEN("AppWorkspace"),
-		0xffeeeeee,
-		&nsoption_colour(sys_colour_AppWorkspace),
-		NULL
-	}, {
-		"Background",
-		SLEN("Background"),
-		0xff0000aa,
-		&nsoption_colour(sys_colour_Background),
-		NULL
-	}, {
-		"ButtonFace",
-		SLEN("ButtonFace"),
-		0xffdddddd,
-		&nsoption_colour(sys_colour_ButtonFace),
-		NULL
-	}, {
-		"ButtonHighlight",
-		SLEN("ButtonHighlight"),
-		0xffcccccc,
-		&nsoption_colour(sys_colour_ButtonHighlight),
-		NULL
-	}, {
-		"ButtonShadow",
-		SLEN("ButtonShadow"),
-		0xffbbbbbb,
-		&nsoption_colour(sys_colour_ButtonShadow),
-		NULL
-	}, {
-		"ButtonText",
-		SLEN("ButtonText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_ButtonText),
-		NULL
-	}, {
-		"CaptionText",
-		SLEN("CaptionText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_CaptionText),
-		NULL
-	}, {
-		"GrayText",
-		SLEN("GrayText"),
-		0xff777777,
-		&nsoption_colour(sys_colour_GrayText),
-		NULL
-	}, {
-		"Highlight",
-		SLEN("Highlight"),
-		0xff0000ee,
-		&nsoption_colour(sys_colour_Highlight),
-		NULL
-	}, {
-		"HighlightText",
-		SLEN("HighlightText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_HighlightText),
-		NULL
-	}, {
-		"InactiveBorder",
-		SLEN("InactiveBorder"),
-		0xff000000,
-		&nsoption_colour(sys_colour_InactiveBorder),
-		NULL
-	}, {
-		"InactiveCaption",
-		SLEN("InactiveCaption"),
-		0xffffffff,
-		&nsoption_colour(sys_colour_InactiveCaption),
-		NULL
-	}, {
-		"InactiveCaptionText",
-		SLEN("InactiveCaptionText"),
-		0xffcccccc,
-		&nsoption_colour(sys_colour_InactiveCaptionText),
-		NULL
-	}, {
-		"InfoBackground",
-		SLEN("InfoBackground"),
-		0xffaaaaaa,
-		&nsoption_colour(sys_colour_InfoBackground),
-		NULL
-	}, {
-		"InfoText",
-		SLEN("InfoText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_InfoText),
-		NULL
-	}, {
-		"Menu",
-		SLEN("Menu"),
-		0xffaaaaaa,
-		&nsoption_colour(sys_colour_Menu),
-		NULL
-	}, {
-		"MenuText",
-		SLEN("MenuText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_MenuText),
-		NULL
-	}, {
-		"Scrollbar",
-		SLEN("Scrollbar"),
-		0xffaaaaaa,
-		&nsoption_colour(sys_colour_Scrollbar),
-		NULL
-	}, {
-		"ThreeDDarkShadow",
-		SLEN("ThreeDDarkShadow"),
-		0xff555555,
-		&nsoption_colour(sys_colour_ThreeDDarkShadow),
-		NULL
-	}, {
-		"ThreeDFace",
-		SLEN("ThreeDFace"),
-		0xffdddddd,
-		&nsoption_colour(sys_colour_ThreeDFace),
-		NULL
-	}, {
-		"ThreeDHighlight",
-		SLEN("ThreeDHighlight"),
-		0xffaaaaaa,
-		&nsoption_colour(sys_colour_ThreeDHighlight),
-		NULL
-	}, {
-		"ThreeDLightShadow",
-		SLEN("ThreeDLightShadow"),
-		0xff999999,
-		&nsoption_colour(sys_colour_ThreeDLightShadow),
-		NULL
-	}, {
-		"ThreeDShadow",
-		SLEN("ThreeDShadow"),
-		0xff777777,
-		&nsoption_colour(sys_colour_ThreeDShadow),
-		NULL
-	}, {
-		"Window",
-		SLEN("Window"),
-		0xffaaaaaa,
-		&nsoption_colour(sys_colour_Window),
-		NULL
-	}, {
-		"WindowFrame",
-		SLEN("WindowFrame"),
-		0xff000000,
-		&nsoption_colour(sys_colour_WindowFrame),
-		NULL
-	}, {
-
-		"WindowText",
-		SLEN("WindowText"),
-		0xff000000,
-		&nsoption_colour(sys_colour_WindowText),
-		NULL
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL)
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name,
-				      colour_list[ccount].length,
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name,
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}
-
-	return CSS_INVALID;
-}
diff --git a/gtk/Makefile.target b/gtk/Makefile.target
index 16b9325..ae67fd7 100644
--- a/gtk/Makefile.target
+++ b/gtk/Makefile.target
@@ -111,7 +111,7 @@ S_GTK := font_pango.c bitmap.c gui.c schedule.c thumbnail.c plotters.c	\
 	treeview.c scaffolding.c gdk.c completion.c login.c throbber.c	\
 	selection.c history.c window.c filetype.c download.c menu.c	\
 	print.c search.c tabs.c theme.c toolbar.c gettext.c		\
-	compat.c cookies.c hotlist.c system_colour.c			\
+	compat.c cookies.c hotlist.c 					\
 	$(addprefix dialogs/,preferences.c about.c source.c)
 
 S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c)
diff --git a/gtk/bitmap.c b/gtk/bitmap.c
index 0f89c67..96e9eda 100644
--- a/gtk/bitmap.c
+++ b/gtk/bitmap.c
@@ -185,11 +185,56 @@ bool bitmap_get_opaque(void *vbitmap)
 unsigned char *bitmap_get_buffer(void *vbitmap)
 {
 	struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+	int pixel_loop;
+	int pixel_count;
+	uint32_t *pixels;
+	uint32_t pixel;
+	cairo_format_t fmt;
+
 	assert(gbitmap);
 	
 	cairo_surface_flush(gbitmap->surface);
+	pixels = (uint32_t *)cairo_image_surface_get_data(gbitmap->surface);
+
+	if (!gbitmap->converted)
+		return (unsigned char *) pixels;
+
+	fmt = cairo_image_surface_get_format(gbitmap->surface);
+	pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
+			cairo_image_surface_get_height(gbitmap->surface);
+
+	if (fmt == CAIRO_FORMAT_RGB24) {
+		for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+			pixel = pixels[pixel_loop];
+			pixels[pixel_loop] = (pixel & 0xff00ff00) |
+				((pixel & 0xff) << 16) |
+				((pixel & 0xff0000) >> 16);
+		}
+	} else {
+		uint32_t t, r, g, b;
+		for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+			pixel = pixels[pixel_loop];
+			t = (pixel & 0xff000000) >> 24;
+			if (t == 0) {
+				pixels[pixel_loop] = 0;
+			} else {
+				r = ((pixel & 0xff0000) >> 8) / t;
+				g = ((pixel & 0xff00)) / t;
+				b = ((pixel & 0xff) << 8) / t;
+
+				r = (r > 255) ? 255 : r;
+				g = (g > 255) ? 255 : g;
+				b = (b > 255) ? 255 : b;
+
+				pixels[pixel_loop] = (t << 24) |
+					(r) | (g << 8) | (b << 16);
+			}
+		}
+	}
+
+	gbitmap->converted = false;
 	
-	return cairo_image_surface_get_data(gbitmap->surface);
+	return (unsigned char *) pixels;
 }
 
 
@@ -286,6 +331,11 @@ void bitmap_modified(void *vbitmap) {
 		cairo_image_surface_get_height(gbitmap->surface);
 	pixels = (uint32_t *)cairo_image_surface_get_data(gbitmap->surface);
 
+	if (gbitmap->converted) {
+		cairo_surface_mark_dirty(gbitmap->surface);
+		return;
+	}
+
 	if (fmt == CAIRO_FORMAT_RGB24) {
 		for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
 			pixel = pixels[pixel_loop];
diff --git a/gtk/completion.c b/gtk/completion.c
index d249db1..a0df08a 100644
--- a/gtk/completion.c
+++ b/gtk/completion.c
@@ -21,7 +21,7 @@
 
 #include "content/urldb.h"
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 GtkListStore *nsgtk_completion_list;
 
diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c
index 2784eb7..0669f8d 100644
--- a/gtk/dialogs/preferences.c
+++ b/gtk/dialogs/preferences.c
@@ -20,7 +20,7 @@
 #include <math.h>
 
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/searchweb.h"
 #include "utils/log.h"
 #include "utils/utils.h"
@@ -45,6 +45,7 @@ struct ppref {
 	GtkEntry *entryProxyHost;
 	GtkEntry *entryProxyUser;
 	GtkEntry *entryProxyPassword;
+	GtkEntry *entryProxyNoproxy;
 	GtkSpinButton *spinProxyPort;
 
 	/* dynamic list stores */
@@ -200,6 +201,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 	gboolean port;
 	gboolean user;
 	gboolean pass;
+	gboolean noproxy;
 
 	switch (proxyval) {
 	case 0: /* no proxy */
@@ -207,6 +209,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 		port = FALSE;
 		user = FALSE;
 		pass = FALSE;
+		noproxy = FALSE;
 		break;
 
 	case 1: /* proxy with no auth */
@@ -214,6 +217,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 		port = TRUE;
 		user = FALSE;
 		pass = FALSE;
+		noproxy = TRUE;
 		break;
 
 	case 2: /* proxy with basic auth */
@@ -221,6 +225,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 		port = TRUE;
 		user = TRUE;
 		pass = TRUE;
+		noproxy = TRUE;
 		break;
 
 	case 3: /* proxy with ntlm auth */
@@ -228,6 +233,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 		port = TRUE;
 		user = TRUE;
 		pass = TRUE;
+		noproxy = TRUE;
 		break;
 
 	case 4: /* system proxy */
@@ -235,6 +241,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 		port = FALSE;
 		user = FALSE;
 		pass = FALSE;
+		noproxy = FALSE;
 		break;
 
 	default:
@@ -245,6 +252,7 @@ static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
 	gtk_widget_set_sensitive(GTK_WIDGET(priv->spinProxyPort), port);
 	gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyUser), user);
 	gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyPassword), pass);
+	gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyNoproxy), noproxy);
 
 }
 
@@ -322,6 +330,9 @@ ENTRY_SIGNALS(entryProxyUser, http_proxy_auth_user)
 /* password */
 ENTRY_SIGNALS(entryProxyPassword, http_proxy_auth_pass)
 
+/* no proxy */
+ENTRY_SIGNALS(entryProxyNoproxy, http_proxy_noproxy)
+
 /* Fetching */
 
 /* maximum fetchers */
@@ -374,7 +385,7 @@ SPINBUTTON_SIGNALS(spinDiscCacheAge, disc_cache_age, 1.0)
 TOGGLEBUTTON_SIGNALS(checkDisablePopups, disable_popups)
 
 /* hide adverts */
-TOGGLEBUTTON_SIGNALS(checkHideAdverts, block_ads)
+TOGGLEBUTTON_SIGNALS(checkHideAdverts, block_advertisements)
 
 /* enable javascript */
 TOGGLEBUTTON_SIGNALS(checkEnableJavascript, enable_javascript)
@@ -999,7 +1010,7 @@ G_MODULE_EXPORT void
 nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
 {
 	if (resid == GTK_RESPONSE_CLOSE) {
-		nsoption_write(options_file_location);
+		nsoption_write(options_file_location, NULL, NULL);
 		gtk_widget_hide(GTK_WIDGET(dlg));
 	}
 }
@@ -1008,7 +1019,7 @@ G_MODULE_EXPORT gboolean
 nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
 						struct ppref *priv)
 {
-	nsoption_write(options_file_location);
+	nsoption_write(options_file_location, NULL, NULL);
 	gtk_widget_hide(GTK_WIDGET(dlg));
 
 	/* delt with it by hiding window, no need to destory widget by
@@ -1019,7 +1030,7 @@ nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
 G_MODULE_EXPORT void
 nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
 {
-	nsoption_write(options_file_location);
+	nsoption_write(options_file_location, NULL, NULL);
 }
 
 
@@ -1069,6 +1080,7 @@ GtkWidget* nsgtk_preferences(struct browser_window *bw, GtkWindow *parent)
 	priv->spinProxyPort = GB(SPIN_BUTTON, spinProxyPort);
 	priv->entryProxyUser = GB(ENTRY, entryProxyUser);
 	priv->entryProxyPassword = GB(ENTRY, entryProxyPassword);
+	priv->entryProxyNoproxy = GB(ENTRY, entryProxyNoproxy);
 #undef GB
 
 	/* connect all signals ready to use */
diff --git a/gtk/dialogs/source.c b/gtk/dialogs/source.c
index c506790..ef4e36e 100644
--- a/gtk/dialogs/source.c
+++ b/gtk/dialogs/source.c
@@ -33,7 +33,7 @@
 #include "desktop/browser_private.h"
 #include "desktop/netsurf.h"
 #include "desktop/print.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/messages.h"
 #include "utils/url.h"
 #include "utils/utils.h"
diff --git a/gtk/download.c b/gtk/download.c
index 71b1aa6..e882ec7 100644
--- a/gtk/download.c
+++ b/gtk/download.c
@@ -30,7 +30,7 @@
 #include "desktop/gui.h"
 #include "gtk/gui.h"
 #include "gtk/scaffolding.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "gtk/download.h"
 #include "gtk/window.h"
 #include "gtk/compat.h"
diff --git a/gtk/font_pango.c b/gtk/font_pango.c
index de115fa..6c7f159 100644
--- a/gtk/font_pango.c
+++ b/gtk/font_pango.c
@@ -34,7 +34,7 @@
 #include "render/font.h"
 #include "utils/utils.h"
 #include "utils/log.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 static bool nsfont_width(const plot_font_style_t *fstyle,
 		const char *string, size_t length,
@@ -253,7 +253,7 @@ bool nsfont_paint(int x, int y, const char *string, size_t length,
 	pango_layout_set_text(layout, string, length);
 	line = pango_layout_get_line(layout, 0);
 	
-	cairo_move_to(current_cr, x, y + 0.5);
+	cairo_move_to(current_cr, x, y);
 	nsgtk_set_colour(fstyle->foreground);
 	pango_cairo_show_layout_line(current_cr, line);
 
diff --git a/gtk/gui.c b/gtk/gui.c
index 5984721..01f9688 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -49,7 +49,7 @@
 #include "desktop/gui.h"
 #include "desktop/history_global_core.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/save_pdf/pdf_plotters.h"
 #include "desktop/searchweb.h"
@@ -241,8 +241,13 @@ nsgtk_init_glade(char **respath)
 	widWarning = GTK_WIDGET(gtk_builder_get_object(gladeWarning, "labelWarning"));
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for gtk frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
 	char *hdir = getenv("HOME");
 	char buf[PATH_MAX];
@@ -252,8 +257,10 @@ void gui_options_init_defaults(void)
 	nsoption_setnull_charp(cookie_file, strdup(buf));
 	nsoption_setnull_charp(cookie_jar, strdup(buf));
 	if (nsoption_charp(cookie_file) == NULL ||
-			nsoption_charp(cookie_jar) == NULL)
-		die("Failed initialising cookie options");
+	    nsoption_charp(cookie_jar) == NULL) {
+		LOG(("Failed initialising cookie options"));
+		return NSERROR_BAD_PARAMETER;
+	}
 
 	if (nsoption_charp(downloads_directory) == NULL) {
 		snprintf(buf, PATH_MAX, "%s/", hdir);
@@ -276,8 +283,18 @@ void gui_options_init_defaults(void)
 			nsoption_charp(ca_path) == NULL ||
 			nsoption_charp(downloads_directory) == NULL ||
 			nsoption_charp(hotlist_path) == NULL) {
-		die("Failed initialising string options");
+		LOG(("Failed initialising string options"));
+		return NSERROR_BAD_PARAMETER;
 	}
+
+	/* set default font names */
+	nsoption_set_charp(font_sans, strdup("Sans"));
+	nsoption_set_charp(font_serif, strdup("Serif"));
+	nsoption_set_charp(font_mono, strdup("Monospace"));
+	nsoption_set_charp(font_cursive, strdup("Serif"));
+	nsoption_set_charp(font_fantasy, strdup("Serif"));
+
+	return NSERROR_OK;
 }
 
 static void check_options(char **respath)
@@ -292,8 +309,8 @@ static void check_options(char **respath)
 	 * The GTK front end now correctly uses it as a proportion of window
 	 * width.  Here we assume that a value of less than 15% is wrong
 	 * and set to the default two thirds. */
-	if (nsoption_int(toolbar_status_width) < 1500) {
-		nsoption_set_int(toolbar_status_width, 6667);
+	if (nsoption_int(toolbar_status_size) < 1500) {
+		nsoption_set_int(toolbar_status_size, 6667);
 	}
 
 	/* user options should be stored in the users home directory */
@@ -308,15 +325,6 @@ static void check_options(char **respath)
 	LOG(("Using '%s' as Print Settings file", buf));
 	print_options_file_location = strdup(buf);
 
-	/* check what the font settings are, setting them to a default font
-	 * if they're not set - stops Pango whinging
-	 */
-#define SETFONTDEFAULT(OPTION,y) if (nsoption_charp(OPTION) == NULL) nsoption_set_charp(OPTION, strdup((y)))
-	SETFONTDEFAULT(font_sans, "Sans");
-	SETFONTDEFAULT(font_serif, "Serif");
-	SETFONTDEFAULT(font_mono, "Monospace");
-	SETFONTDEFAULT(font_cursive, "Serif");
-	SETFONTDEFAULT(font_fantasy, "Serif");
 
 }
 
@@ -355,9 +363,6 @@ static void gui_init(int argc, char** argv, char **respath)
 	nsurl *url;
 	nserror error;
 
-	/* check user options */
-	check_options(respath);
-
 	/* find the languages file */	
 	languages_file_location = filepath_find(respath, "languages");
 	if ((languages_file_location == NULL) || 
@@ -515,12 +520,24 @@ static void nsgtk_check_homedir(void)
 }
 
 /**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+        /* set log stream to be non-buffering */
+	setbuf(fptr, NULL);
+
+	return true;
+}
+
+/**
  * Main entry point from OS.
  */
 int main(int argc, char** argv)
 {
 	char *messages;
 	char *options;
+	nserror ret;
 
 	/* check home directory is available */
 	nsgtk_check_homedir();
@@ -529,25 +546,48 @@ int main(int argc, char** argv)
 
 	gtk_init(&argc, &argv);
 	
-        /* set standard error to be non-buffering */
-	setbuf(stderr, NULL);
-
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(nslog_stream_configure, &argc, argv);
+
+	/* user options setup */
+	ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		fprintf(stderr, "Options failed to initialise (%s)\n",
+			messages_get_errorcode(ret));
+		return 1;
+	}
 	options = filepath_find(respaths, "Choices");
-	messages = filepath_find(respaths, "Messages");
-
-	netsurf_init(&argc, &argv, options, messages);
+	nsoption_read(options, nsoptions);
+	free(options);
+	nsoption_commandline(&argc, argv, nsoptions);
+	check_options(respaths); /* check user options */
 
+	/* common initialisation */
+	messages = filepath_find(respaths, "Messages");
+	ret = netsurf_init(messages);
 	free(messages);
-	free(options);
+	if (ret != NSERROR_OK) {
+		fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
+			messages_get_errorcode(ret));
+		return 1;
+	}
 
+	/* run the browser */
 	gui_init(argc, argv, respaths);
 
 	/* Ensure all scaffoldings are destroyed before we go into exit */
-	while (scaf_list != NULL)
+	while (scaf_list != NULL) {
 		nsgtk_scaffolding_destroy(scaf_list);
+	}
 	
+	/* common finalisation */
 	netsurf_exit();
 
+	/* finalise options */
+	nsoption_finalise(nsoptions, nsoptions_default);
+
 	return 0;
 }
 
diff --git a/gtk/hotlist.c b/gtk/hotlist.c
index d7b5b9e..d249d34 100644
--- a/gtk/hotlist.c
+++ b/gtk/hotlist.c
@@ -18,7 +18,7 @@
 
 
 #include "desktop/hotlist.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/tree.h"
 #include "gtk/gui.h"
diff --git a/gtk/options.h b/gtk/options.h
index 795eca9..612809e 100644
--- a/gtk/options.h
+++ b/gtk/options.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Rob Kendrick <rjek at rjek.com>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -16,68 +16,60 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef _NETSURF_GTK_OPTIONS_H_
 #define _NETSURF_GTK_OPTIONS_H_
 
-#define NSOPTION_EXTRA_DEFINE			\
-	bool render_resample;			\
-	bool downloads_clear;			\
-	bool request_overwrite;			\
-	char *downloads_directory;		\
-	char *url_file;				\
-	bool show_single_tab;			\
-	int button_type;			\
-	bool disable_popups;			\
-	bool disable_plugins;			\
-	int history_age;			\
-	bool hover_urls;			\
-	bool focus_new;				\
-	bool new_blank;				\
-	char *hotlist_path;			\
-	bool source_tab;			\
-	int current_theme;			\
-	int position_tab
-
-#define NSOPTION_EXTRA_DEFAULTS			\
-	.render_resample = true,		\
-	.downloads_clear = false,		\
-	.request_overwrite = true,		\
-	.downloads_directory = NULL,		\
-	.url_file = NULL,			\
-	.show_single_tab = false,		\
-	.button_type = 0,			\
-	.disable_popups = false,		\
-	.disable_plugins = false,		\
-	.history_age = 0,			\
-	.hover_urls = false,			\
-	.focus_new = false,			\
-	.new_blank = false,			\
-	.hotlist_path = NULL,			\
-	.source_tab = false,			\
-	.current_theme = 0,			\
-	.position_tab = 0
-
-#define NSOPTION_EXTRA_TABLE \
-{ "render_resample",	OPTION_BOOL,	&nsoptions.render_resample }, \
-{ "downloads_clear",	OPTION_BOOL,	&nsoptions.downloads_clear }, \
-{ "request_overwrite",	OPTION_BOOL,	&nsoptions.request_overwrite }, \
-{ "downloads_directory",OPTION_STRING,	&nsoptions.downloads_directory }, \
-{ "url_file",		OPTION_STRING,	&nsoptions.url_file }, \
-{ "show_single_tab",    OPTION_BOOL,    &nsoptions.show_single_tab }, \
-{ "button_type",	OPTION_INTEGER, &nsoptions.button_type}, \
-{ "disable_popups",	OPTION_BOOL,	&nsoptions.disable_popups}, \
-{ "disable_plugins",	OPTION_BOOL,	&nsoptions.disable_plugins}, \
-{ "history_age",	OPTION_INTEGER,	&nsoptions.history_age}, \
-{ "hover_urls",		OPTION_BOOL,	&nsoptions.hover_urls}, \
-{ "focus_new",		OPTION_BOOL,	&nsoptions.focus_new}, \
-{ "new_blank",		OPTION_BOOL,	&nsoptions.new_blank}, \
-{ "hotlist_path",	OPTION_STRING,  &nsoptions.hotlist_path}, \
-{ "source_tab",		OPTION_BOOL,	&nsoptions.source_tab},\
-{ "current_theme",	OPTION_INTEGER,	&nsoptions.current_theme}, \
-{ "position_tab",	OPTION_INTEGER,	&nsoptions.position_tab}
+/* currently nothing here */
 
 #endif
+
+/* High quality image scaling */
+NSOPTION_BOOL(render_resample, true)
+
+/* clear downloads */
+NSOPTION_BOOL(downloads_clear, false)
+
+/* prompt before overwriting downloads */
+NSOPTION_BOOL(request_overwrite, true)
+
+/* location to download files to */
+NSOPTION_STRING(downloads_directory, NULL)
+
+/* where to store URL database */
+NSOPTION_STRING(url_file, NULL)
+
+/* Always show tabs even if there is only one */
+NSOPTION_BOOL(show_single_tab, false)
+
+/* size of buttons */
+NSOPTION_INTEGER(button_type, 0)
+
+/* disallow popup windows */
+NSOPTION_BOOL(disable_popups, false)
+
+/* disable content plugins */
+NSOPTION_BOOL(disable_plugins, false)
+
+/* number of days to keep history data */
+NSOPTION_INTEGER(history_age, 0)
+
+/* show urls in local history browser */
+NSOPTION_BOOL(hover_urls, false)
+
+/* bring new tabs to front */
+NSOPTION_BOOL(focus_new, false)
+
+/* new tabs are blank instead of homepage */
+NSOPTION_BOOL(new_blank, false)
+
+/* path to save hotlist file */
+NSOPTION_STRING(hotlist_path, NULL)
+
+/* open source views in a tab */
+NSOPTION_BOOL(source_tab, false)
+
+/* currently selected theme */
+NSOPTION_INTEGER(current_theme, 0)
+
+/* where tabs are positioned */
+NSOPTION_INTEGER(position_tab, 0)
diff --git a/gtk/plotters.c b/gtk/plotters.c
index 3af55b9..2650611 100644
--- a/gtk/plotters.c
+++ b/gtk/plotters.c
@@ -37,7 +37,7 @@
 #include "gtk/plotters.h"
 #include "gtk/scaffolding.h"
 #include "render/font.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "gtk/bitmap.h"
 
 GtkWidget *current_widget;
diff --git a/gtk/print.c b/gtk/print.c
index 02d89bb..68a96dc 100644
--- a/gtk/print.c
+++ b/gtk/print.c
@@ -33,7 +33,7 @@
 
 #include "content/content.h"
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/print.h"
 #include "desktop/printer.h"
diff --git a/gtk/res/options.gtk3.ui b/gtk/res/options.gtk3.ui
index 233825c..a795c2b 100644
--- a/gtk/res/options.gtk3.ui
+++ b/gtk/res/options.gtk3.ui
@@ -2002,7 +2002,7 @@
                           <object class="GtkTable" id="table2">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="n_rows">4</property>
+                            <property name="n_rows">5</property>
                             <property name="n_columns">2</property>
                             <property name="column_spacing">6</property>
                             <property name="row_spacing">6</property>
@@ -2175,6 +2175,36 @@
                                 <property name="bottom_attach">4</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkLabel" id="label55">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">preferencesProxyNoproxy</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkEntry" id="entryProxyNoproxy">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="has_tooltip">True</property>
+                                <property name="tooltip_text" translatable="yes">preferencesProxyNoproxyTooltip</property>
+                                <property name="caps_lock_warning">False</property>
+                                <signal name="changed" handler="nsgtk_preferences_entryProxyNoproxy_changed" swapped="no"/>
+                                <signal name="realize" handler="nsgtk_preferences_entryProxyNoproxy_realize" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                              </packing>
+                            </child>
                           </object>
                         </child>
                       </object>
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index 5abda62..566197d 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -37,7 +37,7 @@
 #include "desktop/hotlist.h"
 #include "desktop/gui.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/print.h"
 #include "desktop/save_complete.h"
@@ -1286,7 +1286,7 @@ MULTIHANDLER(savewindowsize)
 	int x,y,w,h;
 
 	if (GTK_IS_PANED(g->status_pane)) {
-		nsoption_set_int(toolbar_status_width,
+		nsoption_set_int(toolbar_status_size,
 				 gtk_paned_get_position(g->status_pane));
 	}
 	gtk_window_get_position(g->window, &x, &y);
@@ -1297,7 +1297,7 @@ MULTIHANDLER(savewindowsize)
 	nsoption_set_int(window_x, x);
 	nsoption_set_int(window_y, y);
 
-	nsoption_write(options_file_location);
+	nsoption_write(options_file_location, NULL, NULL);
 
 	return TRUE;
 }
diff --git a/gtk/system_colour.c b/gtk/system_colour.c
deleted file mode 100644
index 6c1fd81..0000000
--- a/gtk/system_colour.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ActiveBorder), 
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ActiveCaption), 
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_charp(sys_colour_AppWorkspace), 
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_charp(sys_colour_Background), 
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ButtonFace), 
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ButtonHighlight), 
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_charp(sys_colour_ButtonShadow), 
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ButtonText), 
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_CaptionText), 
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_GrayText), 
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_charp(sys_colour_Highlight), 
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_HighlightText), 
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveBorder), 
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveCaption), 
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_InactiveCaptionText), 
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_InfoBackground), 
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_InfoText), 
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Menu), 
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_MenuText), 
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Scrollbar), 
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_charp(sys_colour_ThreeDDarkShadow), 
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ThreeDFace), 
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ThreeDHighlight), 
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_charp(sys_colour_ThreeDLightShadow), 
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_charp(sys_colour_ThreeDShadow), 
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Window), 
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowFrame), 
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowText), 
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
diff --git a/gtk/tabs.c b/gtk/tabs.c
index e68a192..462f666 100644
--- a/gtk/tabs.c
+++ b/gtk/tabs.c
@@ -24,7 +24,7 @@
 #include "gtk/gui.h"
 #include "desktop/browser.h"
 #include "content/content.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/search.h"
 #include "utils/utils.h"
 #include "gtk/search.h"
diff --git a/gtk/theme.c b/gtk/theme.c
index 402433c..9d50c59 100644
--- a/gtk/theme.c
+++ b/gtk/theme.c
@@ -31,7 +31,7 @@
 #include "gtk/menu.h"
 #include "gtk/theme.h"
 #include "gtk/window.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "gtk/dialogs/preferences.h"
 #include "utils/container.h"
 #include "utils/log.h"
diff --git a/gtk/window.c b/gtk/window.c
index 798181a..5edace8 100644
--- a/gtk/window.c
+++ b/gtk/window.c
@@ -30,7 +30,7 @@
 #include "gtk/window.h"
 #include "desktop/browser_private.h"
 #include "desktop/mouse.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/searchweb.h"
 #include "desktop/textinput.h"
 #include "gtk/compat.h"
@@ -426,8 +426,6 @@ nsgtk_window_scroll_event(GtkWidget *widget,
 	deltax *= nsgtk_adjustment_get_step_increment(hscroll);
 	deltay *= nsgtk_adjustment_get_step_increment(vscroll);
 
-	LOG(("Scrolling %f, %f", deltax, deltay));
-
 	if (browser_window_scroll_at_point(g->bw,
 					   event->x / g->bw->scale,
 					   event->y / g->bw->scale,
@@ -595,12 +593,12 @@ static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget,
 
 	if (g->paned != NULL) {
 		/* Set status bar / scroll bar proportion according to
-		 * option_toolbar_status_width */
+		 * option_toolbar_status_size */
 		/* TODO: Probably want to detect when the user adjusts the
 		 *       status bar width, remember that proportion for the
 		 *       window, and use that here. */
 		gtk_paned_set_position(g->paned, 
-				       (nsoption_int(toolbar_status_width) *
+				       (nsoption_int(toolbar_status_size) *
 					allocation->width) / 10000);
 	}
 
diff --git a/image/gif.c b/image/gif.c
index 704c971..4bd45c7 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -37,7 +37,7 @@
 #include "utils/config.h"
 #include "content/content_protected.h"
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "image/image.h"
 #include "image/bitmap.h"
diff --git a/image/mng.c b/image/mng.c
index 518dc85..325d1d1 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -28,7 +28,7 @@
 #include <time.h>
 #include <libmng.h>
 #include "content/content_protected.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "image/bitmap.h"
 #include "image/mng.h"
diff --git a/javascript/Makefile b/javascript/Makefile
index ac73ee7..693ed65 100644
--- a/javascript/Makefile
+++ b/javascript/Makefile
@@ -35,7 +35,7 @@ D_JSAPI_BINDING += $(patsubst %.c,%.d,$(2))
 
 $(2): $(1) $(OBJROOT)/created
 	$$(VQ)echo " GENBIND: $(1)"
-	$(Q)nsgenbind -I javascript/WebIDL -d $(patsubst %.c,%.d,$(2)) -h $(3) -o $(2) $(1)
+	$(Q)nsgenbind -g -I javascript/WebIDL -d $(patsubst %.c,%.d,$(2)) -h $(3) -o $(2) $(1)
 
 $(3): $(2)
 
diff --git a/javascript/WebIDL/console.idl b/javascript/WebIDL/console.idl
index 309b976..5a3d9eb 100644
--- a/javascript/WebIDL/console.idl
+++ b/javascript/WebIDL/console.idl
@@ -17,4 +17,8 @@ interface Console {
   void timeEnd(DOMString timerName);
   void trace();
   void warn(DOMString msg, Substitition... subst);
+};
+
+partial interface Window {
+  readonly attribute Console console;
 };
\ No newline at end of file
diff --git a/javascript/js.h b/javascript/js.h
index 44de4fe..7102fcf 100644
--- a/javascript/js.h
+++ b/javascript/js.h
@@ -26,6 +26,8 @@
 typedef struct jscontext jscontext;
 typedef struct jsobject jsobject;
 
+typedef bool(jscallback)(void *ctx);
+
 struct dom_document;
 struct dom_node;
 struct dom_string;
@@ -38,9 +40,13 @@ void js_finalise(void);
 
 /** Create a new javascript context.
  *
- * There aare usually one context per browser context
+ * There is usually one context per browser context
+ *
+ * \param timeout elapsed wallclock time (in seconds)  before \a callback is called
+ * \param cb the callback when the runtime exceeds the timeout
+ * \param cbctx The context to pass to the callback
  */
-jscontext *js_newcontext(void);
+jscontext *js_newcontext(int timeout, jscallback *cb, void *cbctx);
 
 /** Destroy a previously created context */
 void js_destroycontext(jscontext *ctx);
diff --git a/javascript/jsapi.c b/javascript/jsapi.c
index 7b68fe9..f8e3889 100644
--- a/javascript/jsapi.c
+++ b/javascript/jsapi.c
@@ -16,6 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <unistd.h>
+#include <signal.h>
+
 #include "javascript/jsapi.h"
 #include "render/html_internal.h"
 #include "content/content.h"
@@ -27,6 +30,8 @@
 #include "window.h"
 #include "event.h"
 
+#define ENABLE_JS_HEARTBEAT 1
+
 static JSRuntime *rt; /* global runtime */
 
 void js_initialise(void)
@@ -56,7 +61,8 @@ void js_finalise(void)
 }
 
 /* The error reporter callback. */
-static void js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
+static void
+js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
 {
 	JSLOG("%s:%u:%s",
 	      report->filename ? report->filename : "<no filename>",
@@ -64,7 +70,250 @@ static void js_reportError(JSContext *cx, const char *message, JSErrorReport *re
 	      message);
 }
 
-jscontext *js_newcontext(void)
+/* heartbeat routines */
+#ifndef ENABLE_JS_HEARTBEAT
+
+struct heartbeat;
+
+/* prepares a context with a heartbeat handler */
+static bool
+setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx)
+{
+	return true;
+}
+
+/* enables the heartbeat on a context */
+static struct heartbeat *enable_heartbeat(JSContext *cx)
+{
+	return NULL;
+}
+
+/* disables heartbeat on a context */
+static bool
+disable_heartbeat(struct heartbeat *hb)
+{
+	return true;
+}
+
+#else
+
+/* private context for heartbeats */
+struct jscontext_priv {
+	int timeout;
+	jscallback *cb;
+	void *cbctx;
+
+	unsigned int branch_reset; /**< reset value for branch counter */
+	unsigned int branch_count; /**< counter for branch callback */
+	time_t last; /**< last time heartbeat happened */
+	time_t end; /**< end time for the current script execution */
+};
+
+/** execution heartbeat */
+static JSBool heartbeat_callback(JSContext *cx)
+{
+	struct jscontext_priv *priv = JS_GetContextPrivate(cx);
+	JSBool ret = JS_TRUE;
+	time_t now = time(NULL);
+
+	/* dynamically update the branch times to ensure we do not get
+	 * called back more than once a second
+	 */
+	if (now == priv->last) {
+		priv->branch_reset = priv->branch_reset * 2;
+	}
+	priv->last = now;
+
+	JSLOG("Running heatbeat at %d end %d", now , priv->end);
+
+	if ((priv->cb != NULL) &&
+	    (now > priv->end)) {
+		if (priv->cb(priv->cbctx) == false) {
+			ret = JS_FALSE; /* abort */
+		} else {
+			priv->end = time(NULL) + priv->timeout;
+		}
+	}
+
+	return ret;
+}
+
+#if JS_VERSION >= 180
+
+struct heartbeat {
+	JSContext *cx;
+	struct sigaction sact; /* signal handler action to restore */
+	int alm; /* alarm value to restore */
+};
+
+static struct heartbeat *cur_hb;
+
+static bool
+setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx)
+{
+	struct jscontext_priv *priv;
+
+	if (timeout == 0) {
+		return true;
+	}
+
+	priv = calloc(1, sizeof(*priv));
+	if (priv == NULL) {
+		return false;
+	}
+
+	priv->timeout = timeout;
+	priv->cb = cb;
+	priv->cbctx = cbctx;
+
+	JS_SetContextPrivate(cx, priv);
+
+	/* if heartbeat is enabled disable JIT or callbacks do not happen */
+	JS_SetOptions(cx, JS_GetOptions(cx) & ~JSOPTION_JIT);
+
+	JS_SetOperationCallback(cx, heartbeat_callback);
+
+	return true;
+}
+
+static void sig_alm_handler(int signum)
+{
+	JS_TriggerOperationCallback(cur_hb->cx);
+	alarm(1);
+	JSDBG("alarm signal handler for context %p", cur_hb->cx);
+}
+
+static struct heartbeat *enable_heartbeat(JSContext *cx)
+{
+	struct jscontext_priv *priv = JS_GetContextPrivate(cx);
+	struct sigaction sact;
+	struct heartbeat *hb;
+
+	if (priv == NULL) {
+		return NULL;
+	}
+
+	priv->last = time(NULL);
+	priv->end = priv->last + priv->timeout;
+
+	hb = malloc(sizeof(*hb));
+	if (hb != NULL) {
+		sigemptyset(&sact.sa_mask);
+		sact.sa_flags = 0;
+		sact.sa_handler = sig_alm_handler;
+		if (sigaction(SIGALRM, &sact, &hb->sact) == 0) {
+			cur_hb = hb;
+			hb->cx = cx;
+			hb->alm = alarm(1);
+		} else {
+			free(hb);
+			hb = NULL;
+			LOG(("Unable to set heartbeat"));
+		}
+	}
+	return hb;
+}
+
+/** disable heartbeat
+ *
+ * /param hb heartbeat to disable may be NULL
+ * /return true on success.
+ */
+static bool
+disable_heartbeat(struct heartbeat *hb)
+{
+	if (hb != NULL) {
+		sigaction(SIGALRM, &hb->sact, NULL); /* restore old handler */
+		alarm(hb->alm); /* restore alarm signal */
+	}
+	return true;
+}
+
+#else
+
+/* need to setup callback to prevent long running scripts infinite
+ * hanging.
+ *
+ * old method is to use:
+ *  JSBranchCallback JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
+ * which gets called a *lot* and should only do something every 5k calls
+ * The callback function
+ *  JSBool (*JSBranchCallback)(JSContext *cx, JSScript *script);
+ * returns JS_TRUE to carry on and JS_FALSE to abort execution
+ * single thread of execution on the context
+ * documented in
+ *   https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_SetBranchCallback
+ *
+ */
+
+#define INITIAL_BRANCH_RESET 5000
+
+struct heartbeat;
+
+static JSBool branch_callback(JSContext *cx, JSScript *script)
+{
+	struct jscontext_priv *priv = JS_GetContextPrivate(cx);
+	JSBool ret = JS_TRUE;
+
+	priv->branch_count--;
+	if (priv->branch_count == 0) {
+		priv->branch_count = priv->branch_reset; /* reset branch count */
+
+		ret = heartbeat_callback(cx);
+	}
+	return ret;
+}
+
+static bool
+setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx)
+{
+	struct jscontext_priv *priv;
+
+	if (timeout == 0) {
+		return true;
+	}
+
+	priv = calloc(1, sizeof(*priv));
+	if (priv == NULL) {
+		return false;
+	}
+
+	priv->timeout = timeout;
+	priv->cb = cb;
+	priv->cbctx = cbctx;
+
+	priv->branch_reset = INITIAL_BRANCH_RESET;
+	priv->branch_count = priv->branch_reset;
+
+	JS_SetContextPrivate(cx, priv);
+
+	JS_SetBranchCallback(cx, branch_callback);
+
+	return true;
+}
+
+static struct heartbeat *enable_heartbeat(JSContext *cx)
+{
+	struct jscontext_priv *priv = JS_GetContextPrivate(cx);
+
+	if (priv != NULL) {
+		priv->last = time(NULL);
+		priv->end = priv->last + priv->timeout;
+	}
+	return NULL;
+}
+
+static bool
+disable_heartbeat(struct heartbeat *hb)
+{
+	return true;
+}
+
+#endif
+
+#endif
+
+jscontext *js_newcontext(int timeout, jscallback *cb, void *cbctx)
 {
 	JSContext *cx;
 
@@ -76,10 +325,16 @@ jscontext *js_newcontext(void)
 	if (cx == NULL) {
 		return NULL;
 	}
-	JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT );
+
+	/* set options on context */
+	JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX | JSOPTION_JIT);
+
 	JS_SetVersion(cx, JSVERSION_LATEST);
 	JS_SetErrorReporter(cx, js_reportError);
 
+	/* run a heartbeat */
+	setup_heartbeat(cx, timeout, cb, cbctx);
+
 	/*JS_SetGCZeal(cx, 2); */
 
 	JSLOG("New Context %p", cx);
@@ -90,9 +345,15 @@ jscontext *js_newcontext(void)
 void js_destroycontext(jscontext *ctx)
 {
 	JSContext *cx = (JSContext *)ctx;
+	struct jscontext_priv *priv;
+
 	if (cx != NULL) {
 		JSLOG("Destroying Context %p", cx);
+		priv = JS_GetContextPrivate(cx);
+
 		JS_DestroyContext(cx);
+
+		free(priv);
 	}
 }
 
@@ -124,10 +385,14 @@ jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
 	return (jsobject *)window;
 }
 
+
+
 bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
 {
 	JSContext *cx = (JSContext *)ctx;
 	jsval rval;
+	JSBool eval_res;
+	struct heartbeat *hb;
 
 	/* JSLOG("%p \"%s\"",cx ,txt); */
 
@@ -143,10 +408,16 @@ bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
 		return false;
 	}
 
-	if (JS_EvaluateScript(cx,
-			      JS_GetGlobalObject(cx),
-			      txt, txtlen,
-			      "<head>", 0, &rval) == JS_TRUE) {
+	hb = enable_heartbeat(cx);
+
+	eval_res = JS_EvaluateScript(cx,
+				     JS_GetGlobalObject(cx),
+				     txt, txtlen,
+				     "<head>", 0, &rval);
+
+	disable_heartbeat(hb);
+
+	if (eval_res == JS_TRUE) {
 
 		return true;
 	}
@@ -168,6 +439,7 @@ bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node
 	dom_exception exc;
 	dom_event *event;
 	dom_string *type_dom;
+	struct heartbeat *hb;
 
 	if (cx == NULL) {
 		return false;
@@ -201,6 +473,8 @@ bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node
 			return false;
 		}
 
+		hb = enable_heartbeat(cx);
+
 		/* dispatch event at the window object */
 		argv[0] = OBJECT_TO_JSVAL(jsevent);
 
@@ -210,6 +484,9 @@ bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node
 					  1,
 					  argv,
 					  &rval);
+
+		disable_heartbeat(hb);
+
 	} else {
 		JSLOG("Dispatching event %s at %p", type, node);
 
@@ -264,15 +541,15 @@ js_dom_event_listener(struct dom_event *event, void *pw)
 		jsevent = jsapi_new_Event(private->cx, NULL, NULL, event);
 		if (jsevent != NULL) {
 
-		/* dispatch event at the window object */
-		event_argv[0] = OBJECT_TO_JSVAL(jsevent);
-
-		JS_CallFunctionValue(private->cx,
-				     NULL,
-				     private->funcval,
-				     1,
-				     event_argv,
-				     &event_rval);
+			/* dispatch event at the window object */
+			event_argv[0] = OBJECT_TO_JSVAL(jsevent);
+
+			JS_CallFunctionValue(private->cx,
+					     NULL,
+					     private->funcval,
+					     1,
+					     event_argv,
+					     &event_rval);
 		}
 	}
 }
diff --git a/javascript/jsapi.h b/javascript/jsapi.h
index e38188a..5b544b8 100644
--- a/javascript/jsapi.h
+++ b/javascript/jsapi.h
@@ -23,12 +23,21 @@
 #ifndef _NETSURF_JAVASCRIPT_JSAPI_H_
 #define _NETSURF_JAVASCRIPT_JSAPI_H_
 
+/* include the correct header */
 #ifdef WITH_MOZJS
 #include "js/jsapi.h"
 #else
 #include "mozjs/jsapi.h"
 #endif
 
+/* logging macros */
+#define JSLOG(args...) LOG((args))
+#ifdef ENABLE_VERBOSE_JS_DEBUG
+#define JSDBG(args...) LOG((args))
+#else
+#define JSDBG(args...)
+#endif
+
 #if JS_VERSION < 180
 
 /************************** Spidermonkey 1.7.0 **************************/
@@ -146,8 +155,10 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx,
 
 #define JSAPI_GCMARK(thing) JS_MarkGCThing(cx, thing, "object", arg)
 
-/* Macros for manipulating GC root */
+#define JSAPI_MARKOP_RETURN(value) return value
+
 
+/* Macros for manipulating GC root */
 #define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj)
 #define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
 
@@ -261,6 +272,8 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx,
 
 #define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT);
 
+#define JSAPI_MARKOP_RETURN(value) return value
+
 /* Macros for manipulating GC root */
 #define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj)
 #define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
@@ -351,21 +364,24 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx,
 
 /* GC marking */
 #ifdef JSCLASS_MARK_IS_TRACE
-/* mark requires casting */
+/* mark function pointer requires casting */
 #define JSAPI_JSCLASS_MARK_IS_TRACE JSCLASS_MARK_IS_TRACE
 #define JSAPI_JSCLASS_MARKOP(x) ((JSMarkOp)x)
 #else
-/* mark does not require casting */
+/* mark function pointer does not require casting */
 #define JSAPI_JSCLASS_MARK_IS_TRACE 0
 #define JSAPI_JSCLASS_MARKOP(x) (x)
 #endif
 
-#define JSAPI_MARKOP(name) JSBool name(JSTracer *trc, JSObject *obj)
+#define JSAPI_MARKOP(name) void name(JSTracer *trc, JSObject *obj)
 
 #define JSAPI_MARKCX trc->context
 
 #define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT);
 
+#define JSAPI_MARKOP_RETURN(value)
+
+
 /* Macros for manipulating GC root */
 #define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddObjectRoot(cx, obj)
 #define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveObjectRoot(cx, obj)
@@ -375,11 +391,6 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx,
 
 #endif
 
-#define JSLOG(args...) LOG((args))
-#ifdef ENABLE_VERBOSE_JS_DEBUG
-#define JSDBG(args...) LOG((args))
-#else
-#define JSDBG(args...)
-#endif
+/************************** **************************/
 
 #endif
diff --git a/javascript/jsapi/htmldocument.bnd b/javascript/jsapi/htmldocument.bnd
index 6e7f565..bd65d7c 100644
--- a/javascript/jsapi/htmldocument.bnd
+++ b/javascript/jsapi/htmldocument.bnd
@@ -60,6 +60,7 @@ binding document {
 }
 
 api finalise %{
+	LOG(("jscontext:%p jsobject:%p private:%p", cx, obj, private));
 	if (private != NULL) {
 		JSLOG("dom_document %p in content %p",
 		     private->node, private->htmlc);
diff --git a/javascript/jsapi/navigator.bnd b/javascript/jsapi/navigator.bnd
index 2fb0c2d..5a0bb39 100644
--- a/javascript/jsapi/navigator.bnd
+++ b/javascript/jsapi/navigator.bnd
@@ -22,8 +22,8 @@ preamble %{
 #include <stdlib.h>
 
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
 #include "utils/config.h"
+#include "utils/nsoption.h"
 #include "utils/useragent.h"
 #include "utils/log.h"
 #include "utils/utsname.h"
diff --git a/javascript/jsapi/window.bnd b/javascript/jsapi/window.bnd
index b334cc7..cecc8fe 100644
--- a/javascript/jsapi/window.bnd
+++ b/javascript/jsapi/window.bnd
@@ -11,6 +11,7 @@
 
 webidlfile "html.idl";
 webidlfile "dom.idl";
+webidlfile "console.idl";
 
 hdrcomment "Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>";
 hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
@@ -61,6 +62,72 @@ struct browser_window *jsapi_get_browser_window(JSContext *cx)
 	return NULL;
 }
 
+static bool
+init_user_prototypes(JSContext *cx,
+		     struct jsclass_private *private,
+		     JSObject *parent)
+{
+	/* Initialises all the user javascript classes to make their
+	 * prototypes available.
+	 */
+	/** @todo should we be managing these prototype objects ourselves */
+	private->prototype_Document = jsapi_InitClass_Document(cx, parent);
+	if (private->prototype_Document == NULL) {
+		return false;
+	}
+
+	private->prototype_Navigator = jsapi_InitClass_Navigator(cx, parent);
+	if (private->prototype_Navigator == NULL) {
+		return false;
+	}
+
+	private->prototype_Location = jsapi_InitClass_Location(cx, parent);
+	if (private->prototype_Location == NULL) {
+		return false;
+	}
+
+	private->prototype_Console = jsapi_InitClass_Console(cx, parent);
+	if (private->prototype_Console == NULL) {
+		return false;
+	}
+
+	private->prototype_HTMLElement = jsapi_InitClass_HTMLElement(cx, parent);
+	if (private->prototype_HTMLElement == NULL) {
+		return false;
+	}
+
+	private->prototype_HTMLCollection = jsapi_InitClass_HTMLCollection(cx, parent);
+	if (private->prototype_HTMLCollection == NULL) {
+		return false;
+	}
+
+	private->prototype_NodeList = jsapi_InitClass_NodeList(cx, parent);
+	if (private->prototype_NodeList == NULL) {
+		return false;
+	}
+
+	private->prototype_Text = jsapi_InitClass_Text(cx, parent);
+	if (private->prototype_Text == NULL) {
+		return false;
+	}
+
+	private->prototype_Comment = jsapi_InitClass_Comment(cx, parent);
+	if (private->prototype_Comment == NULL) {
+		return false;
+	}
+
+	private->prototype_Node = jsapi_InitClass_Node(cx, parent);
+	if (private->prototype_Node == NULL) {
+		return false;
+	}
+
+	private->prototype_Event = jsapi_InitClass_Event(cx, parent);
+	if (private->prototype_Event == NULL) {
+		return false;
+	}
+	return true;
+}
+
 %}
 
 binding window {
@@ -71,23 +138,82 @@ binding window {
 	private "struct browser_window *" bw;
 	private "struct html_content *" htmlc;
 
-	internal "JSObject *" document;
-	internal "JSObject *" navigator;
-	internal "JSObject *" console;
+	/* prototypes held in this object */
+	internal "JSObject *" prototype_Document;
+	internal "JSObject *" prototype_Navigator;
+	internal "JSObject *" prototype_Location;
+	internal "JSObject *" prototype_Console;
+	internal "JSObject *" prototype_HTMLElement;
+	internal "JSObject *" prototype_HTMLCollection;
+	internal "JSObject *" prototype_NodeList;
+	internal "JSObject *" prototype_Text;
+	internal "JSObject *" prototype_Comment;
+	internal "JSObject *" prototype_Node;
+	internal "JSObject *" prototype_Event;
 
+	/** document instantiated on first use */
+	property unshared document;
+
+	/** navigator instantiated on first use */
+	property unshared navigator;
+
+	/** console instantiated on first use */
+	property unshared console;
+
+        /** location is unshared */
+	property unshared location;
+
+	/** @todo instantiate forms, history etc. attributes */
+
+	/* events through a single interface */
 	property unshared type EventHandler;
 }
 
 api mark %{
+
 	if (private != NULL) {
-		if (private->document != NULL) {
-			JSAPI_GCMARK(private->document);
+		if (private->prototype_Document != NULL) {
+			JSAPI_GCMARK(private->prototype_Document);
+		}
+
+		if (private->prototype_Navigator != NULL) {
+			JSAPI_GCMARK(private->prototype_Navigator);
+		}
+
+		if (private->prototype_Location != NULL) {
+			JSAPI_GCMARK(private->prototype_Location);
+		}
+
+		if (private->prototype_Console != NULL) {
+			JSAPI_GCMARK(private->prototype_Console);
+		}
+
+		if (private->prototype_HTMLElement != NULL) {
+			JSAPI_GCMARK(private->prototype_HTMLElement);
 		}
-		if (private->navigator != NULL) {
-			JSAPI_GCMARK(private->navigator);
+
+		if (private->prototype_HTMLCollection != NULL) {
+			JSAPI_GCMARK(private->prototype_HTMLCollection);
+		}
+
+		if (private->prototype_NodeList != NULL) {
+			JSAPI_GCMARK(private->prototype_NodeList);
+		}
+
+		if (private->prototype_Text != NULL) {
+			JSAPI_GCMARK(private->prototype_Text);
+		}
+
+		if (private->prototype_Comment != NULL) {
+			JSAPI_GCMARK(private->prototype_Comment);
 		}
-		if (private->console != NULL) {
-			JSAPI_GCMARK(private->console);
+
+		if (private->prototype_Node != NULL) {
+			JSAPI_GCMARK(private->prototype_Node);
+		}
+
+		if (private->prototype_Event != NULL) {
+			JSAPI_GCMARK(private->prototype_Event);
 		}
 	}
 %}
@@ -96,8 +222,6 @@ api global %{
 %}
 
 api init %{
-	JSObject *user_proto;
-
 	prototype = JS_NewCompartmentAndGlobalObject(cx, &JSClass_Window, NULL);
 	if (prototype == NULL) {
 		return NULL;
@@ -128,65 +252,8 @@ api init %{
 	if (!JS_DefineProperties(cx, prototype, jsclass_properties))
 		return NULL;
 
-	/* Initialises all the user javascript classes to make their
-	 * prototypes available.
-	 */
-	/** @todo should we be managing these prototype objects ourselves */
-	user_proto = jsapi_InitClass_Document(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Navigator(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Location(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Console(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_HTMLElement(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_HTMLCollection(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_NodeList(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Text(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Comment(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Node(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
-	user_proto = jsapi_InitClass_Event(cx, prototype);
-	if (user_proto == NULL) {
-		return NULL;
-	}
-
+	/* as the global just got changed, force a GC run */
+	JS_GC(cx);
 %}
 
 api new %{
@@ -196,32 +263,45 @@ api new %{
 	/* the window object is the global so its prototype *is* the instance */
 	newobject = prototype;
 
-	/* instantiate the subclasses off the window global */
-	private->document = jsapi_new_Document(cx,
-					       NULL,
-					       newobject,
-					       (dom_document *)dom_node_ref(htmlc->document),
-					       htmlc);
-	if (private->document == NULL) {
+	if (init_user_prototypes(cx, private, prototype) == false) {
+		/* prototype initialisation failed */
 		free(private);
 		return NULL;
 	}
 
-	private->navigator = jsapi_new_Navigator(cx, NULL, newobject);
-	if (private->navigator == NULL) {
-		free(private);
-		return NULL;
+	LOG(("Created new window object %p", newobject));
+%}
+
+getter document %{
+	if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
+		/* already created - return it */
+		return JS_TRUE;
 	}
 
-	private->console = jsapi_new_Console(cx, NULL, newobject);
-	if (private->console == NULL) {
-		free(private);
-		return NULL;
+	/* instantiate the subclasses off the window global */
+	jsret = jsapi_new_Document(cx,
+				   NULL,
+				   NULL,
+				   (dom_document *)dom_node_ref(private->htmlc->document),
+				   private->htmlc);
+%}
+
+getter navigator %{
+	if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
+		/* already created - return it */
+		return JS_TRUE;
 	}
 
-	/** @todo forms, history */
+	jsret = jsapi_new_Navigator(cx, NULL, NULL);
+%}
 
-	LOG(("Created new window object %p", newobject));
+getter console %{
+	if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
+		/* already created - return it */
+		return JS_TRUE;
+	}
+
+	jsret = jsapi_new_Console(cx, NULL, NULL);
 %}
 
 operation confirm %{
@@ -273,9 +353,21 @@ operation dispatchEvent %{
 %}
 
 getter location %{
+	if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
+		/* already created - return it */
+		return JS_TRUE;
+	}
+
+/* should get the docuemnts location
 	jsval loc;
 	JS_GetProperty(cx, private->document, "location", &loc);
 	jsret = JSVAL_TO_OBJECT(loc);
+*/
+
+	jsret = jsapi_new_Location(cx,
+				   NULL,
+				   NULL,
+				   llcache_handle_get_url(private->htmlc->base.llcache));
 %}
 
 getter window %{
@@ -286,6 +378,11 @@ getter self %{
 	jsret = obj;
 %}
 
+/* very iffy implementation */
+getter top %{
+	jsret = obj;
+%}
+
 getter EventHandler %{
 	/* this implementation is unique to the window object as it is
 	 * not a dom node.
diff --git a/javascript/none.c b/javascript/none.c
index 3e7b39c..d4b8ce5 100644
--- a/javascript/none.c
+++ b/javascript/none.c
@@ -21,7 +21,7 @@
  */
 
 #include "content/content.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 
 #include "javascript/js.h"
 #include "utils/log.h"
@@ -35,7 +35,7 @@ void js_finalise(void)
 {
 }
 
-jscontext *js_newcontext(void)
+jscontext *js_newcontext(int timeout, jscallback *cb, void *cbctx)
 {
 	return NULL;
 }
diff --git a/monkey/Makefile.target b/monkey/Makefile.target
index 05a32d0..6c60ca1 100644
--- a/monkey/Makefile.target
+++ b/monkey/Makefile.target
@@ -66,7 +66,7 @@ endif
 # ----------------------------------------------------------------------------
 
 # S_MONKEY are sources purely for the MONKEY build
-S_MONKEY := main.c utils.c filetype.c schedule.c system_colour.c	\
+S_MONKEY := main.c utils.c filetype.c schedule.c \
             bitmap.c plot.c browser.c download.c thumbnail.c		\
             401login.c cert.c font.c poll.c dispatch.c
 
diff --git a/monkey/font.c b/monkey/font.c
index 7f390a4..a45b7fd 100644
--- a/monkey/font.c
+++ b/monkey/font.c
@@ -18,7 +18,7 @@
 
 #include "css/css.h"
 #include "render/font.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/utf8.h"
 
 
diff --git a/monkey/main.c b/monkey/main.c
index 03421ef..e806b0e 100644
--- a/monkey/main.c
+++ b/monkey/main.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 
 #include "monkey/filetype.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "monkey/poll.h"
 #include "monkey/dispatch.h"
 #include "monkey/browser.h"
@@ -31,6 +31,7 @@
 #include "desktop/gui.h"
 #include "desktop/netsurf.h"
 #include "desktop/sslcert.h"
+#include "utils/log.h"
 #include "utils/filepath.h"
 #include "utils/url.h"
 
@@ -91,10 +92,27 @@ static void quit_handler(int argc, char **argv)
   netsurf_quit = true;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for monkey frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
+{
+  /* currently no default overrides */
+  return NSERROR_OK;
+}
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
 {
-  /* Set defaults for absent option strings */
+  /* set log stream to be non-buffering */
+  setbuf(fptr, NULL);
+
+  return true;
 }
 
 int
@@ -103,7 +121,8 @@ main(int argc, char **argv)
   char *messages;
   char *options;
   char buf[PATH_MAX];
-  
+  nserror ret;
+
   /* Unbuffer stdin/out/err */
   setbuf(stdin, NULL);
   setbuf(stdout, NULL);
@@ -111,14 +130,29 @@ main(int argc, char **argv)
   
   /* Prep the search paths */
   respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./monkey/res");
-  
+
+  /* initialise logging. Not fatal if it fails but not much we can do
+   * about it either.
+   */
+  nslog_init(nslog_stream_configure, &argc, argv);
+
+  /* user options setup */
+  ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+  if (ret != NSERROR_OK) {
+    die("Options failed to initialise");
+  }
   options = filepath_find(respaths, "Choices");
-  messages = filepath_find(respaths, "Messages");
+  nsoption_read(options, nsoptions);
+  free(options);
+  nsoption_commandline(&argc, argv, nsoptions);
 
-  netsurf_init(&argc, &argv, options, messages);
-  
+  /* common initialisation */
+  messages = filepath_find(respaths, "Messages");
+  ret = netsurf_init(messages);
   free(messages);
-  free(options);
+  if (ret != NSERROR_OK) {
+    die("NetSurf failed to initialise");
+  }
     
   filepath_sfinddef(respaths, buf, "mime.types", "/etc/");
   gtk_fetch_filetype_init(buf);
@@ -139,5 +173,9 @@ main(int argc, char **argv)
   
   netsurf_exit();
   fprintf(stdout, "GENERIC FINISHED\n");
+
+  /* finalise options */
+  nsoption_finalise(nsoptions, nsoptions_default);
+
   return 0;
 }
diff --git a/monkey/options.h b/monkey/options.h
index 88fb7e1..57cce7e 100644
--- a/monkey/options.h
+++ b/monkey/options.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Rob Kendrick <rjek at rjek.com>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -16,66 +16,28 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef _NETSURF_MONKEY_OPTIONS_H_
 #define _NETSURF_MONKEY_OPTIONS_H_
 
-#define NSOPTION_EXTRA_DEFINE			\
-	bool render_resample;			\
-	bool downloads_clear;			\
-	bool request_overwrite;			\
-	char *downloads_directory;		\
-	char *url_file;				\
-	bool show_single_tab;			\
-	int button_type;			\
-	bool disable_popups;			\
-	bool disable_plugins;			\
-	int history_age;			\
-	bool hover_urls;			\
-	bool focus_new;				\
-	bool new_blank;				\
-	char *hotlist_path;			\
-	bool source_tab;			\
-	int current_theme
+/* currently nothing here */
 
-#define NSOPTION_EXTRA_DEFAULTS			\
-	.render_resample = true,		\
-	.downloads_clear = false,		\
-	.request_overwrite = true,		\
-	.downloads_directory = NULL,		\
-	.url_file = NULL,			\
-	.show_single_tab = false,		\
-	.button_type = 0,			\
-	.disable_popups = false,		\
-	.disable_plugins = false,		\
-	.history_age = 0,			\
-	.hover_urls = false,			\
-	.focus_new = false,			\
-	.new_blank = false,			\
-	.hotlist_path = NULL,			\
-	.source_tab = false,			\
-	.current_theme = 0			
+#endif
 
-#define NSOPTION_EXTRA_TABLE \
-{ "render_resample",	OPTION_BOOL,	&nsoptions.render_resample }, \
-{ "downloads_clear",	OPTION_BOOL,	&nsoptions.downloads_clear }, \
-{ "request_overwrite",	OPTION_BOOL,	&nsoptions.request_overwrite }, \
-{ "downloads_directory",OPTION_STRING,	&nsoptions.downloads_directory }, \
-{ "url_file",		OPTION_STRING,	&nsoptions.url_file }, \
-{ "show_single_tab",    OPTION_BOOL,    &nsoptions.show_single_tab }, \
-{ "button_type",	OPTION_INTEGER, &nsoptions.button_type}, \
-{ "disable_popups",	OPTION_BOOL,	&nsoptions.disable_popups}, \
-{ "disable_plugins",	OPTION_BOOL,	&nsoptions.disable_plugins}, \
-{ "history_age",	OPTION_INTEGER,	&nsoptions.history_age}, \
-{ "hover_urls",		OPTION_BOOL,	&nsoptions.hover_urls}, \
-{ "focus_new",		OPTION_BOOL,	&nsoptions.focus_new}, \
-{ "new_blank",		OPTION_BOOL,	&nsoptions.new_blank}, \
-{ "hotlist_path",	OPTION_STRING,  &nsoptions.hotlist_path}, \
-{ "source_tab",		OPTION_BOOL,	&nsoptions.source_tab},\
-{ "current_theme",	OPTION_INTEGER,	&nsoptions.current_theme}
+NSOPTION_BOOL(render_resample, true)
+NSOPTION_BOOL(downloads_clear, false)
+NSOPTION_BOOL(request_overwrite, true)
+NSOPTION_STRING(downloads_directory, NULL)
+NSOPTION_STRING(url_file, NULL)
+NSOPTION_BOOL(show_single_tab, false)
+NSOPTION_INTEGER(button_type, 0)
+NSOPTION_BOOL(disable_popups, false)
+NSOPTION_BOOL(disable_plugins, false)
+NSOPTION_INTEGER(history_age, 0)
+NSOPTION_BOOL(hover_urls, false)
+NSOPTION_BOOL(focus_new, false)
+NSOPTION_BOOL(new_blank, false)
+NSOPTION_STRING(hotlist_path, NULL)
+NSOPTION_BOOL(source_tab, false)
+NSOPTION_INTEGER(current_theme, 0)
 
 
-#endif
diff --git a/monkey/system_colour.c b/monkey/system_colour.c
deleted file mode 100644
index 6c1fd81..0000000
--- a/monkey/system_colour.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ActiveBorder), 
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ActiveCaption), 
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_charp(sys_colour_AppWorkspace), 
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_charp(sys_colour_Background), 
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ButtonFace), 
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ButtonHighlight), 
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_charp(sys_colour_ButtonShadow), 
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ButtonText), 
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_CaptionText), 
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_GrayText), 
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_charp(sys_colour_Highlight), 
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_HighlightText), 
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveBorder), 
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveCaption), 
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_InactiveCaptionText), 
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_InfoBackground), 
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_InfoText), 
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Menu), 
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_MenuText), 
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Scrollbar), 
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_charp(sys_colour_ThreeDDarkShadow), 
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ThreeDFace), 
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ThreeDHighlight), 
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_charp(sys_colour_ThreeDLightShadow), 
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_charp(sys_colour_ThreeDShadow), 
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Window), 
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowFrame), 
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowText), 
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}
diff --git a/render/box.c b/render/box.c
index 5dfada0..1f2c9fe 100644
--- a/render/box.c
+++ b/render/box.c
@@ -34,7 +34,7 @@
 #include "css/utils.h"
 #include "css/dump.h"
 #include "desktop/scrollbar.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "render/box.h"
 #include "render/form.h"
 #include "render/html_internal.h"
diff --git a/render/box_construct.c b/render/box_construct.c
index 78d0f67..03e87e8 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -36,7 +36,7 @@
 #include "css/css.h"
 #include "css/utils.h"
 #include "css/select.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "render/box.h"
 #include "render/box_textarea.h"
 #include "render/form.h"
diff --git a/render/font.c b/render/font.c
index a98a89a..03c5a36 100644
--- a/render/font.c
+++ b/render/font.c
@@ -18,7 +18,7 @@
 
 #include "css/css.h"
 #include "css/utils.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "render/font.h"
 
 static plot_font_generic_family_t plot_font_generic_family(
diff --git a/render/html.c b/render/html.c
index 364083b..8fb35f8 100644
--- a/render/html.c
+++ b/render/html.c
@@ -32,7 +32,7 @@
 #include "content/content_protected.h"
 #include "content/fetch.h"
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/selection.h"
 #include "desktop/scrollbar.h"
 #include "desktop/textarea.h"
@@ -145,423 +145,6 @@ static void html_box_convert_done(html_content *c, bool success)
 }
 
 
-/**
- * Complete conversion of an HTML document
- *
- * \param c  Content to convert
- */
-void html_finish_conversion(html_content *c)
-{
-	union content_msg_data msg_data;
-	dom_exception exc; /* returned by libdom functions */
-	dom_node *html;
-	nserror error;
-
-	/* Bail out if we've been aborted */
-	if (c->aborted) {
-		content_broadcast_errorcode(&c->base, NSERROR_STOPPED);
-		content_set_error(&c->base);
-		return;
-	}
-
-	/* create new css selection context */
-	error = html_css_new_selection_context(c, &c->select_ctx);
-	if (error != NSERROR_OK) {
-		content_broadcast_errorcode(&c->base, error);
-		content_set_error(&c->base);
-		return;
-	}
-
-
-	/* fire a simple event named load at the Document's Window
-	 * object, but with its target set to the Document object (and
-	 * the currentTarget set to the Window object)
-	 */
-	js_fire_event(c->jscontext, "load", c->document, NULL);
-
-	/* convert dom tree to box tree */
-	LOG(("DOM to box (%p)", c));
-	content_set_status(&c->base, messages_get("Processing"));
-	msg_data.explicit_status_text = NULL;
-	content_broadcast(&c->base, CONTENT_MSG_STATUS, msg_data);
-
-	exc = dom_document_get_document_element(c->document, (void *) &html);
-	if ((exc != DOM_NO_ERR) || (html == NULL)) {
-		LOG(("error retrieving html element from dom"));
-		content_broadcast_errorcode(&c->base, NSERROR_DOM);
-		content_set_error(&c->base);
-		return;
-	}
-
-	error = dom_to_box(html, c, html_box_convert_done);
-	if (error != NSERROR_OK) {
-		dom_node_unref(html);
-		html_object_free_objects(c);
-		content_broadcast_errorcode(&c->base, error);
-		content_set_error(&c->base);
-		return;
-	}
-
-	dom_node_unref(html);
-}
-
-/* callback for DOMNodeInserted end type */
-static void
-dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw)
-{
-	dom_event_target *node;
-	dom_node_type type;
-	dom_string *name;
-	dom_exception exc;
-	html_content *htmlc = pw;
-
-	exc = dom_event_get_target(evt, &node);
-	if ((exc == DOM_NO_ERR) && (node != NULL)) {
-		exc = dom_node_get_node_type(node, &type);
-		if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
-			/* an element node has been inserted */
-			exc = dom_node_get_node_name(node, &name);
-			if ((exc == DOM_NO_ERR) && (name != NULL)) {
-				/* LOG(("element htmlc:%p node %p name:%s", htmlc, node, dom_string_data(name))); */
-				if (dom_string_caseless_isequal(name, corestring_dom_link)) {
-					html_css_process_link(htmlc, (dom_node *)node);
-				}
-
-				dom_string_unref(name);
-			}
-		}
-		dom_node_unref(node);
-	}
-}
-
-/* callback for DOMNodeInserted end type */
-static void
-dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
-{
-	dom_event_target *node;
-	dom_node_type type;
-	dom_string *name;
-	dom_exception exc;
-	html_content *htmlc = pw;
-
-	exc = dom_event_get_target(evt, &node);
-	if ((exc == DOM_NO_ERR) && (node != NULL)) {
-		exc = dom_node_get_node_type(node, &type);
-		if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
-			/* an element node has been inserted */
-			exc = dom_node_get_node_name(node, &name);
-			if ((exc == DOM_NO_ERR) && (name != NULL)) {
-				/* LOG(("element htmlc:%p node:%p name:%s", htmlc, node, dom_string_data(name)));  */
-				if (dom_string_caseless_isequal(name, corestring_dom_style)) {
-					html_css_update_style(htmlc, (dom_node *)node);
-				} 
-
-				dom_string_unref(name);
-			}
-		}
-		dom_node_unref(node);
-	}
-}
-
-/* callback function selector
- *
- * selects a callback function for libdom to call based on the type and phase.
- * dom_default_action_phase from events/document_event.h
- *
- * The principle events are:
- *   DOMSubtreeModified
- *   DOMAttrModified
- *   DOMNodeInserted
- *   DOMNodeInsertedIntoDocument
- *
- * @return callback function pointer or NULL for none
- */
-static dom_default_action_callback
-dom_event_fetcher(dom_string *type,
-		  dom_default_action_phase phase,
-		  void **pw)
-{
-	//LOG(("type:%s", dom_string_data(type)));
-
-	if (phase == DOM_DEFAULT_ACTION_END) {
-		if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) {
-			return dom_default_action_DOMNodeInserted_cb;
-		} else if (dom_string_isequal(type, corestring_dom_DOMSubtreeModified)) {
-			return dom_default_action_DOMSubtreeModified_cb;
-		}
-	}
-	return NULL;
-}
-
-static nserror
-html_create_html_data(html_content *c, const http_parameter *params)
-{
-	lwc_string *charset;
-	nserror nerror;
-	dom_hubbub_parser_params parse_params;
-	dom_hubbub_error error;
-
-	c->parser = NULL;
-	c->document = NULL;
-	c->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
-	c->encoding = NULL;
-	c->base_url = nsurl_ref(content_get_url(&c->base));
-	c->base_target = NULL;
-	c->aborted = false;
-	c->bctx = NULL;
-	c->layout = NULL;
-	c->background_colour = NS_TRANSPARENT;
-	c->stylesheet_count = 0;
-	c->stylesheets = NULL;
-	c->select_ctx = NULL;
-	c->universal = NULL;
-	c->num_objects = 0;
-	c->object_list = NULL;
-	c->forms = NULL;
-	c->imagemaps = NULL;
-	c->bw = NULL;
-	c->frameset = NULL;
-	c->iframe = NULL;
-	c->page = NULL;
-	c->font_func = &nsfont;
-	c->drag_type = HTML_DRAG_NONE;
-	c->drag_owner.no_owner = true;
-	c->selection_type = HTML_SELECTION_NONE;
-	c->selection_owner.none = true;
-	c->focus_type = HTML_FOCUS_SELF;
-	c->focus_owner.self = true;
-	c->search = NULL;
-	c->search_string = NULL;
-	c->scripts_count = 0;
-	c->scripts = NULL;
-	c->jscontext = NULL;
-
-	c->base.active = 1; /* The html content itself is active */
-
-	if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
-		return NSERROR_NOMEM;
-	}
-
-	selection_prepare(&c->sel, (struct content *)c, true);
-
-	nerror = http_parameter_list_find_item(params, corestring_lwc_charset, &charset);
-	if (nerror == NSERROR_OK) {
-		c->encoding = strdup(lwc_string_data(charset));
-
-		lwc_string_unref(charset);
-
-		if (c->encoding == NULL) {
-			lwc_string_unref(c->universal);
-			c->universal = NULL;
-			return NSERROR_NOMEM;
-
-		}
-		c->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER;
-	}
-
-	/* Create the parser binding */
-	parse_params.enc = c->encoding;
-	parse_params.fix_enc = true;
-	parse_params.enable_script = nsoption_bool(enable_javascript);
-	parse_params.msg = NULL;
-	parse_params.script = html_process_script;
-	parse_params.ctx = c;
-	parse_params.daf = dom_event_fetcher;
-
-	error = dom_hubbub_parser_create(&parse_params,
-					 &c->parser,
-					 &c->document);
-	if ((error != DOM_HUBBUB_OK) && (c->encoding != NULL)) {
-		/* Ok, we don't support the declared encoding. Bailing out
-		 * isn't exactly user-friendly, so fall back to autodetect */
-		free(c->encoding);
-		c->encoding = NULL;
-
-		parse_params.enc = c->encoding;
-
-		error = dom_hubbub_parser_create(&parse_params,
-						 &c->parser,
-						 &c->document);
-	}
-	if (error != DOM_HUBBUB_OK) {
-		nsurl_unref(c->base_url);
-		c->base_url = NULL;
-
-		lwc_string_unref(c->universal);
-		c->universal = NULL;
-
-		return libdom_hubbub_error_to_nserror(error);
-	}
-
-	return NSERROR_OK;
-
-}
-
-/**
- * Create a CONTENT_HTML.
- *
- * The content_html_data structure is initialized and the HTML parser is
- * created.
- */
-
-static nserror
-html_create(const content_handler *handler,
-	    lwc_string *imime_type,
-	    const http_parameter *params,
-	    llcache_handle *llcache,
-	    const char *fallback_charset,
-	    bool quirks,
-	    struct content **c)
-{
-	html_content *html;
-	nserror error;
-
-	html = calloc(1, sizeof(html_content));
-	if (html == NULL)
-		return NSERROR_NOMEM;
-
-	error = content__init(&html->base, handler, imime_type, params,
-			llcache, fallback_charset, quirks);
-	if (error != NSERROR_OK) {
-		free(html);
-		return error;
-	}
-
-	error = html_create_html_data(html, params);
-	if (error != NSERROR_OK) {
-		content_broadcast_errorcode(&html->base, error);
-		free(html);
-		return error;
-	}
-
-	error = html_css_new_stylesheets(html);
-	if (error != NSERROR_OK) {
-		content_broadcast_errorcode(&html->base, error);
-		free(html);
-		return error;
-	}
-
-	*c = (struct content *) html;
-
-	return NSERROR_OK;
-}
-
-
-
-static nserror
-html_process_encoding_change(struct content *c, 
-			     const char *data, 
-			     unsigned int size)
-{
-	html_content *html = (html_content *) c;
-	dom_hubbub_parser_params parse_params;
-	dom_hubbub_error error;
-	const char *encoding;
-	const char *source_data;
-	unsigned long source_size;
-
-	/* Retrieve new encoding */
-	encoding = dom_hubbub_parser_get_encoding(html->parser, 
-						  &html->encoding_source);
-	if (encoding == NULL) {
-		return NSERROR_NOMEM;
-	}
-
-	if (html->encoding != NULL) {
-		free(html->encoding);
-	}
-
-	html->encoding = strdup(encoding);
-	if (html->encoding == NULL) {
-		return NSERROR_NOMEM;
-	}
-
-	/* Destroy binding */
-	dom_hubbub_parser_destroy(html->parser);
-	html->parser = NULL;
-
-	if (html->document != NULL) {
-		dom_node_unref(html->document);
-	}
-
-	parse_params.enc = html->encoding;
-	parse_params.fix_enc = true;
-	parse_params.enable_script = nsoption_bool(enable_javascript);
-	parse_params.msg = NULL;
-	parse_params.script = html_process_script;
-	parse_params.ctx = html;
-	parse_params.daf = dom_event_fetcher;
-
-	/* Create new binding, using the new encoding */
-	error = dom_hubbub_parser_create(&parse_params,
-					 &html->parser,
-					 &html->document);
-	if (error != DOM_HUBBUB_OK) {
-		/* Ok, we don't support the declared encoding. Bailing out
-		 * isn't exactly user-friendly, so fall back to Windows-1252 */
-		free(html->encoding);
-		html->encoding = strdup("Windows-1252");
-		if (html->encoding == NULL) {
-			return NSERROR_NOMEM;
-		}
-		parse_params.enc = html->encoding;
-
-		error = dom_hubbub_parser_create(&parse_params,
-						 &html->parser,
-						 &html->document);
-
-		if (error != DOM_HUBBUB_OK) {
-			return libdom_hubbub_error_to_nserror(error);
-		}
-
-	}
-
-	source_data = content__get_source_data(c, &source_size);
-
-	/* Reprocess all the data.  This is safe because
-	 * the encoding is now specified at parser start which means
-	 * it cannot be changed again. 
-	 */
-	error = dom_hubbub_parser_parse_chunk(html->parser, 
-					      (const uint8_t *)source_data, 
-					      source_size);
-
-	return libdom_hubbub_error_to_nserror(error);
-}
-
-
-/**
- * Process data for CONTENT_HTML.
- */
-
-static bool
-html_process_data(struct content *c, const char *data, unsigned int size)
-{
-	html_content *html = (html_content *) c;
-	dom_hubbub_error dom_ret;
-	nserror err = NSERROR_OK; /* assume its all going to be ok */
-
-	dom_ret = dom_hubbub_parser_parse_chunk(html->parser, 
-					      (const uint8_t *) data, 
-					      size);
-
-	err = libdom_hubbub_error_to_nserror(dom_ret);
-
-	/* deal with encoding change */
-	if (err == NSERROR_ENCODING_CHANGE) {
-		 err = html_process_encoding_change(c, data, size);
-	}
-
-	/* broadcast the error if necessary */
-	if (err != NSERROR_OK) {
-		content_broadcast_errorcode(c, err);
-		return false;
-	}
-
-	return true;	
-}
-
-
 /** process link node */
 static bool html_process_link(html_content *c, dom_node *node)
 {
@@ -660,9 +243,6 @@ static bool html_process_title(html_content *c, dom_node *node)
 	char *title_str;
 	bool success;
 
-	if (c->base.title != NULL)
-		return true;
-
 	exc = dom_node_get_text_content(node, &title);
 	if ((exc != DOM_NO_ERR) || (title == NULL)) {
 		return false;
@@ -705,381 +285,677 @@ static bool html_process_base(html_content *c, dom_node *node)
 	}
 
 
-	/* get target attribute if present and not already set */
-	if (c->base_target != NULL) {
-		return true;
+	/* get target attribute if present and not already set */
+	if (c->base_target != NULL) {
+		return true;
+	}
+
+	exc = dom_element_get_attribute(node,
+			corestring_dom_target, &atr_string);
+	if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
+		/* Validation rules from the HTML5 spec for the base element:
+		 *  The target must be one of _blank, _self, _parent, or
+		 *  _top or any identifier which does not begin with an
+		 *  underscore
+		 */
+		if (*dom_string_data(atr_string) != '_' ||
+				dom_string_caseless_lwc_isequal(atr_string,
+						corestring_lwc__blank) ||
+				dom_string_caseless_lwc_isequal(atr_string,
+						corestring_lwc__self) ||
+				dom_string_caseless_lwc_isequal(atr_string,
+						corestring_lwc__parent) ||
+				dom_string_caseless_lwc_isequal(atr_string,
+						corestring_lwc__top)) {
+			c->base_target = strdup(dom_string_data(atr_string));
+		}
+		dom_string_unref(atr_string);
+	}
+
+	return true;
+}
+
+static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
+{
+	union content_msg_data msg_data;
+	const char *url, *end, *refresh = NULL;
+	char *new_url;
+	char quote = '\0';
+	dom_string *equiv, *content;
+	dom_exception exc;
+	nsurl *nsurl;
+	nserror error = NSERROR_OK;
+
+	exc = dom_element_get_attribute(n, corestring_dom_http_equiv, &equiv);
+	if (exc != DOM_NO_ERR) {
+		return NSERROR_DOM;
+	}
+
+	if (equiv == NULL) {
+		return NSERROR_OK;
+	}
+
+	if (!dom_string_caseless_lwc_isequal(equiv, corestring_lwc_refresh)) {
+		dom_string_unref(equiv);
+		return NSERROR_OK;
+	}
+
+	dom_string_unref(equiv);
+
+	exc = dom_element_get_attribute(n, corestring_dom_content, &content);
+	if (exc != DOM_NO_ERR) {
+		return NSERROR_DOM;
+	}
+
+	if (content == NULL) {
+		return NSERROR_OK;
+	}
+
+	end = dom_string_data(content) + dom_string_byte_length(content);
+
+	/* content  := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS]
+	 * intpart  := 1*DIGIT
+	 * fracpart := 1*('.' | DIGIT)
+	 * url      := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq)
+	 * url-nq   := *urlchar
+	 * url-sq   := "'" *(urlchar | '"') "'"
+	 * url-dq   := '"' *(urlchar | "'") '"'
+	 * urlchar  := [#x9#x21#x23-#x26#x28-#x7E] | nonascii
+	 * nonascii := [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
+	 */
+
+	url = dom_string_data(content);
+
+	/* *LWS */
+	while (url < end && isspace(*url)) {
+		url++;
+	}
+
+	/* intpart */
+	if (url == end || (*url < '0' || '9' < *url)) {
+		/* Empty content, or invalid timeval */
+		dom_string_unref(content);
+		return NSERROR_OK;
+	}
+
+	msg_data.delay = (int) strtol(url, &new_url, 10);
+	/* a very small delay and self-referencing URL can cause a loop
+	 * that grinds machines to a halt. To prevent this we set a
+	 * minimum refresh delay of 1s. */
+	if (msg_data.delay < 1) {
+		msg_data.delay = 1;
+	}
+
+	url = new_url;
+
+	/* fracpart? (ignored, as delay is integer only) */
+	while (url < end && (('0' <= *url && *url <= '9') ||
+			*url == '.')) {
+		url++;
+	}
+
+	/* *LWS */
+	while (url < end && isspace(*url)) {
+		url++;
+	}
+
+	/* ';' */
+	if (url < end && *url == ';')
+		url++;
+
+	/* *LWS */
+	while (url < end && isspace(*url)) {
+		url++;
+	}
+
+	if (url == end) {
+		/* Just delay specified, so refresh current page */
+		dom_string_unref(content);
+
+		c->base.refresh = nsurl_ref(
+				content_get_url(&c->base));
+
+		content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+
+		return NSERROR_OK;
+	}
+
+	/* "url" */
+	if (url <= end - 3) {
+		if (strncasecmp(url, "url", 3) == 0) {
+			url += 3;
+		} else {
+			/* Unexpected input, ignore this header */
+			dom_string_unref(content);
+			return NSERROR_OK;
+		}
+	} else {
+		/* Insufficient input, ignore this header */
+		dom_string_unref(content);
+		return NSERROR_OK;
+	}
+
+	/* *LWS */
+	while (url < end && isspace(*url)) {
+		url++;
+	}
+
+	/* '=' */
+	if (url < end) {
+		if (*url == '=') {
+			url++;
+		} else {
+			/* Unexpected input, ignore this header */
+			dom_string_unref(content);
+			return NSERROR_OK;
+		}
+	} else {
+		/* Insufficient input, ignore this header */
+		dom_string_unref(content);
+		return NSERROR_OK;
+	}
+
+	/* *LWS */
+	while (url < end && isspace(*url)) {
+		url++;
+	}
+
+	/* '"' or "'" */
+	if (url < end && (*url == '"' || *url == '\'')) {
+		quote = *url;
+		url++;
+	}
+
+	/* Start of URL */
+	refresh = url;
+
+	if (quote != 0) {
+		/* url-sq | url-dq */
+		while (url < end && *url != quote)
+			url++;
+	} else {
+		/* url-nq */
+		while (url < end && !isspace(*url))
+			url++;
+	}
+
+	/* '"' or "'" or *LWS (we don't care) */
+	if (url > refresh) {
+		/* There's a URL */
+		new_url = strndup(refresh, url - refresh);
+		if (new_url == NULL) {
+			dom_string_unref(content);
+			return NSERROR_NOMEM;
+		}
+
+		error = nsurl_join(c->base_url, new_url, &nsurl);
+		if (error == NSERROR_OK) {
+			/* broadcast valid refresh url */
+
+			c->base.refresh = nsurl;
+
+			content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+			c->refresh = true;
+		}
+
+		free(new_url);
+
+	}
+
+	dom_string_unref(content);
+
+	return error;
+}
+
+
+/**
+ * Complete conversion of an HTML document
+ *
+ * \param c  Content to convert
+ */
+void html_finish_conversion(html_content *c)
+{
+	union content_msg_data msg_data;
+	dom_exception exc; /* returned by libdom functions */
+	dom_node *html;
+	nserror error;
+
+	/* Bail out if we've been aborted */
+	if (c->aborted) {
+		content_broadcast_errorcode(&c->base, NSERROR_STOPPED);
+		content_set_error(&c->base);
+		return;
+	}
+
+	/* create new css selection context */
+	error = html_css_new_selection_context(c, &c->select_ctx);
+	if (error != NSERROR_OK) {
+		content_broadcast_errorcode(&c->base, error);
+		content_set_error(&c->base);
+		return;
+	}
+
+
+	/* fire a simple event named load at the Document's Window
+	 * object, but with its target set to the Document object (and
+	 * the currentTarget set to the Window object)
+	 */
+	js_fire_event(c->jscontext, "load", c->document, NULL);
+
+	/* convert dom tree to box tree */
+	LOG(("DOM to box (%p)", c));
+	content_set_status(&c->base, messages_get("Processing"));
+	msg_data.explicit_status_text = NULL;
+	content_broadcast(&c->base, CONTENT_MSG_STATUS, msg_data);
+
+	exc = dom_document_get_document_element(c->document, (void *) &html);
+	if ((exc != DOM_NO_ERR) || (html == NULL)) {
+		LOG(("error retrieving html element from dom"));
+		content_broadcast_errorcode(&c->base, NSERROR_DOM);
+		content_set_error(&c->base);
+		return;
 	}
 
-	exc = dom_element_get_attribute(node,
-			corestring_dom_target, &atr_string);
-	if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
-		/* Validation rules from the HTML5 spec for the base element:
-		 *  The target must be one of _blank, _self, _parent, or
-		 *  _top or any identifier which does not begin with an
-		 *  underscore
-		 */
-		if (*dom_string_data(atr_string) != '_' ||
-		    dom_string_caseless_lwc_isequal(atr_string,
-		    		corestring_lwc__blank) ||
-		    dom_string_caseless_lwc_isequal(atr_string,
-		    		corestring_lwc__self) ||
-		    dom_string_caseless_lwc_isequal(atr_string,
-		    		corestring_lwc__parent) ||
-		    dom_string_caseless_lwc_isequal(atr_string,
-		    		corestring_lwc__top)) {
-			c->base_target = strdup(dom_string_data(atr_string));
-		}
-		dom_string_unref(atr_string);
+	error = dom_to_box(html, c, html_box_convert_done);
+	if (error != NSERROR_OK) {
+		dom_node_unref(html);
+		html_object_free_objects(c);
+		content_broadcast_errorcode(&c->base, error);
+		content_set_error(&c->base);
+		return;
 	}
 
-	return true;
+	dom_node_unref(html);
 }
 
-/**
- * Process elements in <head>.
- *
- * \param  c     content structure
- * \param  head  xml node of head element
- * \return  true on success, false on memory exhaustion
- *
- * The title and base href are extracted if present.
- */
-
-static nserror html_head(html_content *c, dom_node *head)
+/* callback for DOMNodeInserted end type */
+static void
+dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw)
 {
-	dom_node *node;
-	dom_exception exc; /* returned by libdom functions */
-	dom_string *node_name;
-	dom_node_type node_type;
-	dom_node *next_node;
-
-	exc = dom_node_get_first_child(head, &node);
-	if (exc != DOM_NO_ERR) {
-		return NSERROR_DOM;
-	}
-
-	while (node != NULL) {
-		exc = dom_node_get_node_type(node, &node_type);
+	dom_event_target *node;
+	dom_node_type type;
+	dom_string *name;
+	dom_exception exc;
+	html_content *htmlc = pw;
 
-		if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
-			exc = dom_node_get_node_name(node, &node_name);
+	exc = dom_event_get_target(evt, &node);
+	if ((exc == DOM_NO_ERR) && (node != NULL)) {
+		exc = dom_node_get_node_type(node, &type);
+		if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
+			/* an element node has been inserted */
+			exc = dom_node_get_node_name(node, &name);
+			if ((exc == DOM_NO_ERR) && (name != NULL)) {
 
-			if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
-				if (dom_string_caseless_lwc_isequal(
-						node_name,
-						corestring_lwc_title)) {
-					html_process_title(c, node);
+				if (dom_string_caseless_isequal(name,
+						corestring_dom_link)) {
+					/* Handle stylesheet loading */
+					html_css_process_link(htmlc,
+							(dom_node *)node);
+					/* Generic link handling */
+					html_process_link(htmlc,
+							(dom_node *)node);
+
+				} else if (dom_string_caseless_lwc_isequal(name,
+						corestring_lwc_meta) &&
+						htmlc->refresh == false) {
+					html_meta_refresh_process_element(htmlc,
+							(dom_node *)node);
 				} else if (dom_string_caseless_lwc_isequal(
-						node_name,
-						corestring_lwc_base)) {
-					html_process_base(c, node);
+						name, corestring_lwc_base)) {
+					html_process_base(htmlc,
+							(dom_node *)node);
 				} else if (dom_string_caseless_lwc_isequal(
-						node_name,
-						corestring_lwc_link)) {
-					html_process_link(c, node);
+						name, corestring_lwc_title) &&
+						htmlc->title == NULL) {
+					htmlc->title = dom_node_ref(node);
 				}
-			}
-			if (node_name != NULL) {
-				dom_string_unref(node_name);
+
+				dom_string_unref(name);
 			}
 		}
-
-		/* move to next node */
-		exc = dom_node_get_next_sibling(node, &next_node);
 		dom_node_unref(node);
-		if (exc == DOM_NO_ERR) {
-			node = next_node;
-		} else {
-			node = NULL;
-		}
 	}
-
-	return NSERROR_OK;
 }
 
-static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
+/* callback for DOMNodeInserted end type */
+static void
+dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
 {
-	union content_msg_data msg_data;
-	const char *url, *end, *refresh = NULL;
-	char *new_url;
-	char quote = '\0';
-	dom_string *equiv, *content;
+	dom_event_target *node;
+	dom_node_type type;
+	dom_string *name;
 	dom_exception exc;
-	nsurl *nsurl;
-	nserror error = NSERROR_OK;
+	html_content *htmlc = pw;
 
-	exc = dom_element_get_attribute(n, corestring_dom_http_equiv, &equiv);
-	if (exc != DOM_NO_ERR) {
-		return NSERROR_DOM;
-	}
+	exc = dom_event_get_target(evt, &node);
+	if ((exc == DOM_NO_ERR) && (node != NULL)) {
+		if (htmlc->title == (dom_node *)node) {
+			/* Node is our title node */
+			html_process_title(htmlc, (dom_node *)node);
+			dom_node_unref(node);
+			return;
+		}
 
-	if (equiv == NULL) {
-		return NSERROR_OK;
-	}
+		exc = dom_node_get_node_type(node, &type);
+		if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
+			/* an element node has been modified */
+			exc = dom_node_get_node_name(node, &name);
+			if ((exc == DOM_NO_ERR) && (name != NULL)) {
 
-	if (!dom_string_caseless_lwc_isequal(equiv, corestring_lwc_refresh)) {
-		dom_string_unref(equiv);
-		return NSERROR_OK;
+				if (dom_string_caseless_isequal(name,
+						corestring_dom_style)) {
+					html_css_update_style(htmlc,
+							(dom_node *)node);
+				}
+
+				dom_string_unref(name);
+			}
+		}
+		dom_node_unref(node);
 	}
+}
 
-	dom_string_unref(equiv);
+/* callback function selector
+ *
+ * selects a callback function for libdom to call based on the type and phase.
+ * dom_default_action_phase from events/document_event.h
+ *
+ * The principle events are:
+ *   DOMSubtreeModified
+ *   DOMAttrModified
+ *   DOMNodeInserted
+ *   DOMNodeInsertedIntoDocument
+ *
+ * @return callback function pointer or NULL for none
+ */
+static dom_default_action_callback
+dom_event_fetcher(dom_string *type,
+		  dom_default_action_phase phase,
+		  void **pw)
+{
+	//LOG(("type:%s", dom_string_data(type)));
 
-	exc = dom_element_get_attribute(n, corestring_dom_content, &content);
-	if (exc != DOM_NO_ERR) {
-		return NSERROR_DOM;
+	if (phase == DOM_DEFAULT_ACTION_END) {
+		if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) {
+			return dom_default_action_DOMNodeInserted_cb;
+		} else if (dom_string_isequal(type, corestring_dom_DOMSubtreeModified)) {
+			return dom_default_action_DOMSubtreeModified_cb;
+		}
 	}
+	return NULL;
+}
 
-	if (content == NULL) {
-		return NSERROR_OK;
+static nserror
+html_create_html_data(html_content *c, const http_parameter *params)
+{
+	lwc_string *charset;
+	nserror nerror;
+	dom_hubbub_parser_params parse_params;
+	dom_hubbub_error error;
+
+	c->parser = NULL;
+	c->document = NULL;
+	c->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
+	c->encoding = NULL;
+	c->base_url = nsurl_ref(content_get_url(&c->base));
+	c->base_target = NULL;
+	c->aborted = false;
+	c->refresh = false;
+	c->title = NULL;
+	c->bctx = NULL;
+	c->layout = NULL;
+	c->background_colour = NS_TRANSPARENT;
+	c->stylesheet_count = 0;
+	c->stylesheets = NULL;
+	c->select_ctx = NULL;
+	c->universal = NULL;
+	c->num_objects = 0;
+	c->object_list = NULL;
+	c->forms = NULL;
+	c->imagemaps = NULL;
+	c->bw = NULL;
+	c->frameset = NULL;
+	c->iframe = NULL;
+	c->page = NULL;
+	c->font_func = &nsfont;
+	c->drag_type = HTML_DRAG_NONE;
+	c->drag_owner.no_owner = true;
+	c->selection_type = HTML_SELECTION_NONE;
+	c->selection_owner.none = true;
+	c->focus_type = HTML_FOCUS_SELF;
+	c->focus_owner.self = true;
+	c->search = NULL;
+	c->search_string = NULL;
+	c->scripts_count = 0;
+	c->scripts = NULL;
+	c->jscontext = NULL;
+
+	c->base.active = 1; /* The html content itself is active */
+
+	if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
+		return NSERROR_NOMEM;
 	}
 
-	end = dom_string_data(content) + dom_string_byte_length(content);
+	selection_prepare(&c->sel, (struct content *)c, true);
 
-	/* content  := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS]
-	 * intpart  := 1*DIGIT
-	 * fracpart := 1*('.' | DIGIT)
-	 * url      := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq)
-	 * url-nq   := *urlchar
-	 * url-sq   := "'" *(urlchar | '"') "'"
-	 * url-dq   := '"' *(urlchar | "'") '"'
-	 * urlchar  := [#x9#x21#x23-#x26#x28-#x7E] | nonascii
-	 * nonascii := [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
-	 */
+	nerror = http_parameter_list_find_item(params, corestring_lwc_charset, &charset);
+	if (nerror == NSERROR_OK) {
+		c->encoding = strdup(lwc_string_data(charset));
 
-	url = dom_string_data(content);
+		lwc_string_unref(charset);
 
-	/* *LWS */
-	while (url < end && isspace(*url)) {
-		url++;
-	}
+		if (c->encoding == NULL) {
+			lwc_string_unref(c->universal);
+			c->universal = NULL;
+			return NSERROR_NOMEM;
 
-	/* intpart */
-	if (url == end || (*url < '0' || '9' < *url)) {
-		/* Empty content, or invalid timeval */
-		dom_string_unref(content);
-		return NSERROR_OK;
+		}
+		c->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER;
 	}
 
-	msg_data.delay = (int) strtol(url, &new_url, 10);
-	/* a very small delay and self-referencing URL can cause a loop
-	 * that grinds machines to a halt. To prevent this we set a
-	 * minimum refresh delay of 1s. */
-	if (msg_data.delay < 1) {
-		msg_data.delay = 1;
-	}
+	/* Create the parser binding */
+	parse_params.enc = c->encoding;
+	parse_params.fix_enc = true;
+	parse_params.enable_script = nsoption_bool(enable_javascript);
+	parse_params.msg = NULL;
+	parse_params.script = html_process_script;
+	parse_params.ctx = c;
+	parse_params.daf = dom_event_fetcher;
 
-	url = new_url;
+	error = dom_hubbub_parser_create(&parse_params,
+					 &c->parser,
+					 &c->document);
+	if ((error != DOM_HUBBUB_OK) && (c->encoding != NULL)) {
+		/* Ok, we don't support the declared encoding. Bailing out
+		 * isn't exactly user-friendly, so fall back to autodetect */
+		free(c->encoding);
+		c->encoding = NULL;
 
-	/* fracpart? (ignored, as delay is integer only) */
-	while (url < end && (('0' <= *url && *url <= '9') ||
-			*url == '.')) {
-		url++;
-	}
+		parse_params.enc = c->encoding;
 
-	/* *LWS */
-	while (url < end && isspace(*url)) {
-		url++;
+		error = dom_hubbub_parser_create(&parse_params,
+						 &c->parser,
+						 &c->document);
 	}
+	if (error != DOM_HUBBUB_OK) {
+		nsurl_unref(c->base_url);
+		c->base_url = NULL;
 
-	/* ';' */
-	if (url < end && *url == ';')
-		url++;
+		lwc_string_unref(c->universal);
+		c->universal = NULL;
 
-	/* *LWS */
-	while (url < end && isspace(*url)) {
-		url++;
+		return libdom_hubbub_error_to_nserror(error);
 	}
 
-	if (url == end) {
-		/* Just delay specified, so refresh current page */
-		dom_string_unref(content);
+	return NSERROR_OK;
 
-		c->base.refresh = nsurl_ref(
-				content_get_url(&c->base));
+}
 
-		content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+/**
+ * Create a CONTENT_HTML.
+ *
+ * The content_html_data structure is initialized and the HTML parser is
+ * created.
+ */
 
-		return NSERROR_OK;
+static nserror
+html_create(const content_handler *handler,
+	    lwc_string *imime_type,
+	    const http_parameter *params,
+	    llcache_handle *llcache,
+	    const char *fallback_charset,
+	    bool quirks,
+	    struct content **c)
+{
+	html_content *html;
+	nserror error;
+
+	html = calloc(1, sizeof(html_content));
+	if (html == NULL)
+		return NSERROR_NOMEM;
+
+	error = content__init(&html->base, handler, imime_type, params,
+			llcache, fallback_charset, quirks);
+	if (error != NSERROR_OK) {
+		free(html);
+		return error;
 	}
 
-	/* "url" */
-	if (url <= end - 3) {
-		if (strncasecmp(url, "url", 3) == 0) {
-			url += 3;
-		} else {
-			/* Unexpected input, ignore this header */
-			dom_string_unref(content);
-			return NSERROR_OK;
-		}
-	} else {
-		/* Insufficient input, ignore this header */
-		dom_string_unref(content);
-		return NSERROR_OK;
+	error = html_create_html_data(html, params);
+	if (error != NSERROR_OK) {
+		content_broadcast_errorcode(&html->base, error);
+		free(html);
+		return error;
 	}
 
-	/* *LWS */
-	while (url < end && isspace(*url)) {
-		url++;
+	error = html_css_new_stylesheets(html);
+	if (error != NSERROR_OK) {
+		content_broadcast_errorcode(&html->base, error);
+		free(html);
+		return error;
 	}
 
-	/* '=' */
-	if (url < end) {
-		if (*url == '=') {
-			url++;
-		} else {
-			/* Unexpected input, ignore this header */
-			dom_string_unref(content);
-			return NSERROR_OK;
-		}
-	} else {
-		/* Insufficient input, ignore this header */
-		dom_string_unref(content);
-		return NSERROR_OK;
+	*c = (struct content *) html;
+
+	return NSERROR_OK;
+}
+
+
+
+static nserror
+html_process_encoding_change(struct content *c, 
+			     const char *data, 
+			     unsigned int size)
+{
+	html_content *html = (html_content *) c;
+	dom_hubbub_parser_params parse_params;
+	dom_hubbub_error error;
+	const char *encoding;
+	const char *source_data;
+	unsigned long source_size;
+
+	/* Retrieve new encoding */
+	encoding = dom_hubbub_parser_get_encoding(html->parser, 
+						  &html->encoding_source);
+	if (encoding == NULL) {
+		return NSERROR_NOMEM;
 	}
 
-	/* *LWS */
-	while (url < end && isspace(*url)) {
-		url++;
+	if (html->encoding != NULL) {
+		free(html->encoding);
 	}
 
-	/* '"' or "'" */
-	if (url < end && (*url == '"' || *url == '\'')) {
-		quote = *url;
-		url++;
+	html->encoding = strdup(encoding);
+	if (html->encoding == NULL) {
+		return NSERROR_NOMEM;
 	}
 
-	/* Start of URL */
-	refresh = url;
+	/* Destroy binding */
+	dom_hubbub_parser_destroy(html->parser);
+	html->parser = NULL;
 
-	if (quote != 0) {
-		/* url-sq | url-dq */
-		while (url < end && *url != quote)
-			url++;
-	} else {
-		/* url-nq */
-		while (url < end && !isspace(*url))
-			url++;
+	if (html->document != NULL) {
+		dom_node_unref(html->document);
 	}
 
-	/* '"' or "'" or *LWS (we don't care) */
-	if (url > refresh) {
-		/* There's a URL */
-		new_url = strndup(refresh, url - refresh);
-		if (new_url == NULL) {
-			dom_string_unref(content);
+	parse_params.enc = html->encoding;
+	parse_params.fix_enc = true;
+	parse_params.enable_script = nsoption_bool(enable_javascript);
+	parse_params.msg = NULL;
+	parse_params.script = html_process_script;
+	parse_params.ctx = html;
+	parse_params.daf = dom_event_fetcher;
+
+	/* Create new binding, using the new encoding */
+	error = dom_hubbub_parser_create(&parse_params,
+					 &html->parser,
+					 &html->document);
+	if (error != DOM_HUBBUB_OK) {
+		/* Ok, we don't support the declared encoding. Bailing out
+		 * isn't exactly user-friendly, so fall back to Windows-1252 */
+		free(html->encoding);
+		html->encoding = strdup("Windows-1252");
+		if (html->encoding == NULL) {
 			return NSERROR_NOMEM;
 		}
+		parse_params.enc = html->encoding;
 
-		error = nsurl_join(c->base_url, new_url, &nsurl);
-		if (error == NSERROR_OK) {
-			/* broadcast valid refresh url */
-
-			c->base.refresh = nsurl;
+		error = dom_hubbub_parser_create(&parse_params,
+						 &html->parser,
+						 &html->document);
 
-			content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+		if (error != DOM_HUBBUB_OK) {
+			return libdom_hubbub_error_to_nserror(error);
 		}
 
-		free(new_url);
-
 	}
 
-	dom_string_unref(content);
+	source_data = content__get_source_data(c, &source_size);
 
-	return error;
+	/* Reprocess all the data.  This is safe because
+	 * the encoding is now specified at parser start which means
+	 * it cannot be changed again. 
+	 */
+	error = dom_hubbub_parser_parse_chunk(html->parser, 
+					      (const uint8_t *)source_data, 
+					      source_size);
+
+	return libdom_hubbub_error_to_nserror(error);
 }
 
+
 /**
- * Search for meta refresh
- *
- * http://wp.netscape.com/assist/net_sites/pushpull.html
- *
- * \param c content structure
- * \param head xml node of head element
- * \return true on success, false otherwise (error reported)
+ * Process data for CONTENT_HTML.
  */
 
-static nserror html_meta_refresh(html_content *c, dom_node *head)
+static bool
+html_process_data(struct content *c, const char *data, unsigned int size)
 {
-	dom_node *n, *next;
-	dom_exception exc;
-	nserror ns_error = NSERROR_OK;
-
-	if (head == NULL) {
-		return ns_error;
-	}
-
-	exc = dom_node_get_first_child(head, &n);
-	if (exc != DOM_NO_ERR) {
-		return NSERROR_DOM;
-	}
-
-	while (n != NULL) {
-		dom_node_type type;
-
-		exc = dom_node_get_node_type(n, &type);
-		if (exc != DOM_NO_ERR) {
-			dom_node_unref(n);
-			return NSERROR_DOM;
-		}
-
-		if (type == DOM_ELEMENT_NODE) {
-			dom_string *name;
+	html_content *html = (html_content *) c;
+	dom_hubbub_error dom_ret;
+	nserror err = NSERROR_OK; /* assume its all going to be ok */
 
-			exc = dom_node_get_node_name(n, &name);
-			if (exc != DOM_NO_ERR) {
-				dom_node_unref(n);
-				return NSERROR_DOM;
-			}
+	dom_ret = dom_hubbub_parser_parse_chunk(html->parser, 
+					      (const uint8_t *) data, 
+					      size);
 
-			/* Recurse into noscript elements */
-			if (dom_string_caseless_lwc_isequal(name, corestring_lwc_noscript)) {
-				ns_error = html_meta_refresh(c, n);
-				if (ns_error != NSERROR_OK) {
-					/* Some error occurred */
-					dom_string_unref(name);
-					dom_node_unref(n);
-					return ns_error;
-				} else if (c->base.refresh != NULL) {
-					/* Meta refresh found - stop */
-					dom_string_unref(name);
-					dom_node_unref(n);
-					return NSERROR_OK;
-				}
-			} else if (dom_string_caseless_lwc_isequal(name, corestring_lwc_meta)) {
-				ns_error = html_meta_refresh_process_element(c, n);
-				if (ns_error != NSERROR_OK) {
-					/* Some error occurred */
-					dom_string_unref(name);
-					dom_node_unref(n);
-					return ns_error;
-				} else if (c->base.refresh != NULL) {
-					/* Meta refresh found - stop */
-					dom_string_unref(name);
-					dom_node_unref(n);
-					return NSERROR_OK;
-				}
-			}
-			dom_string_unref(name);
-		}
+	err = libdom_hubbub_error_to_nserror(dom_ret);
 
-		exc = dom_node_get_next_sibling(n, &next);
-		if (exc != DOM_NO_ERR) {
-			dom_node_unref(n);
-			return NSERROR_DOM;
-		}
+	/* deal with encoding change */
+	if (err == NSERROR_ENCODING_CHANGE) {
+		 err = html_process_encoding_change(c, data, size);
+	}
 
-		dom_node_unref(n);
-		n = next;
+	/* broadcast the error if necessary */
+	if (err != NSERROR_OK) {
+		content_broadcast_errorcode(c, err);
+		return false;
 	}
 
-	return ns_error;
+	return true;	
 }
 
 
-
-
-
-
 /**
  * Convert a CONTENT_HTML for display.
  *
@@ -1134,25 +1010,22 @@ static bool html_convert(struct content *c)
 bool html_can_begin_conversion(html_content *htmlc)
 {
 	unsigned int i;
-	bool got_modified_stylesheet = false;
+
+	if (htmlc->base.active != 0)
+		return false;
 
 	for (i = 0; i != htmlc->stylesheet_count; i++) {
-		if (htmlc->stylesheets[i].modified) {
-			got_modified_stylesheet = true;
-			break;
-		}
+		if (htmlc->stylesheets[i].modified)
+			return false;
 	}
 
-	if (htmlc->base.active != 0 || got_modified_stylesheet)
-		return false;
-
 	return true;
 }
 
 bool
 html_begin_conversion(html_content *htmlc)
 {
-	dom_node *html, *head;
+	dom_node *html;
 	nserror ns_error;
 	struct form *f;
 	dom_exception exc; /* returned by libdom functions */
@@ -1224,28 +1097,6 @@ html_begin_conversion(html_content *htmlc)
 	}
 	dom_string_unref(node_name);
 
-	head = libdom_find_first_element(html, corestring_lwc_head);
-	if (head != NULL) {
-		ns_error = html_head(htmlc, head);
-		if (ns_error != NSERROR_OK) {
-			content_broadcast_errorcode(&htmlc->base, ns_error);
-
-			dom_node_unref(html);
-			dom_node_unref(head);
-			return false;
-		}
-
-		/* handle meta refresh */
-		ns_error = html_meta_refresh(htmlc, head);
-		if (ns_error != NSERROR_OK) {
-			content_broadcast_errorcode(&htmlc->base, ns_error);
-
-			dom_node_unref(html);
-			dom_node_unref(head);
-			return false;
-		}
-	}
-
 	/* Retrieve forms from parser */
 	htmlc->forms = html_forms_get_forms(htmlc->encoding,
 			(dom_html_document *) htmlc->document);
@@ -1269,7 +1120,6 @@ html_begin_conversion(html_content *htmlc)
 			content_broadcast_errorcode(&htmlc->base, ns_error);
 
 			dom_node_unref(html);
-			dom_node_unref(head);
 			return false;
 		}
 
@@ -1281,7 +1131,6 @@ html_begin_conversion(html_content *htmlc)
 						    NSERROR_NOMEM);
 
 			dom_node_unref(html);
-			dom_node_unref(head);
 			return false;
 		}
 
@@ -1292,13 +1141,11 @@ html_begin_conversion(html_content *htmlc)
 				content_broadcast_errorcode(&htmlc->base, 
 							    NSERROR_NOMEM);
 				dom_node_unref(html);
-				dom_node_unref(head);
 				return false;
 			}
 		}
 	}
 
-	dom_node_unref(head);
 	dom_node_unref(html);
 
 	if (htmlc->base.active == 0) {
@@ -1380,8 +1227,8 @@ static void html_reformat(struct content *c, int width, int height)
 
 	time_taken = wallclock() - time_before;
 	c->reformat_time = wallclock() +
-		((time_taken * 3 < nsoption_int(min_reflow_period) ?
-		  nsoption_int(min_reflow_period) : time_taken * 3));
+		((time_taken * 3 < nsoption_uint(min_reflow_period) ?
+		  nsoption_uint(min_reflow_period) : time_taken * 3));
 }
 
 
@@ -1512,6 +1359,12 @@ static void html_destroy(struct content *c)
 
 	if (html->document != NULL) {
 		dom_node_unref(html->document);
+		html->document = NULL;
+	}
+
+	if (html->title != NULL) {
+		dom_node_unref(html->title);
+		html->title = NULL;
 	}
 
 	/* Free base target */
diff --git a/render/html_css.c b/render/html_css.c
index 7c09620..bf20dcf 100644
--- a/render/html_css.c
+++ b/render/html_css.c
@@ -28,7 +28,7 @@
 #include <stdlib.h>
 
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "render/html_internal.h"
 #include "utils/corestrings.h"
 #include "utils/config.h"
@@ -103,6 +103,9 @@ html_convert_css_callback(hlcache_handle *css,
 	case CONTENT_MSG_READY:
 		break;
 
+	case CONTENT_MSG_REDIRECT:
+		break;
+
 	case CONTENT_MSG_DONE:
 		LOG(("done stylesheet slot %d '%s'", i,
 				nsurl_access(hlcache_handle_get_url(css))));
@@ -551,7 +554,7 @@ nserror html_css_new_stylesheets(html_content *c)
 	LOG(("%d fetches active", c->base.active));
 
 
-	if (nsoption_bool(block_ads)) {
+	if (nsoption_bool(block_advertisements)) {
 		ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
 				0, content_get_url(&c->base), NULL,
 				html_convert_css_callback,
diff --git a/render/html_interaction.c b/render/html_interaction.c
index 7c3de2a..6f4d9bd 100644
--- a/render/html_interaction.c
+++ b/render/html_interaction.c
@@ -32,7 +32,7 @@
 #include "desktop/browser.h"
 #include "desktop/frames.h"
 #include "desktop/mouse.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/scrollbar.h"
 #include "desktop/selection.h"
 #include "desktop/textarea.h"
diff --git a/render/html_internal.h b/render/html_internal.h
index b491f19..43fce9b 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -90,6 +90,12 @@ typedef struct html_content {
 	/** Content has been aborted in the LOADING state */
 	bool aborted;
 
+	/** Whether a meta refresh has been handled */
+	bool refresh;
+
+	/* Title element node */
+	dom_node *title;
+
         /** A talloc context purely for the render box tree */
 	int *bctx;
 	/** Box tree, or NULL. */
diff --git a/render/html_object.c b/render/html_object.c
index d4d0ff9..aad0dac 100644
--- a/render/html_object.c
+++ b/render/html_object.c
@@ -28,7 +28,7 @@
 #include <stdlib.h>
 
 #include "content/hlcache.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/scrollbar.h"
 #include "render/box.h"
 #include "render/html_internal.h"
@@ -203,6 +203,7 @@ html_object_callback(hlcache_handle *object,
 		break;
 
 	case CONTENT_MSG_REFORMAT:
+	case CONTENT_MSG_REDIRECT:
 		break;
 
 	case CONTENT_MSG_REDRAW:
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 91df897..13cffe6 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -38,7 +38,7 @@
 #include "css/utils.h"
 #include "desktop/plotters.h"
 #include "desktop/selection.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/print.h"
 #include "desktop/scrollbar.h"
 #include "desktop/textarea.h"
@@ -2065,8 +2065,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
 		if (r.y0 < clip->y0) r.y0 = clip->y0;
 		if (clip->x1 < r.x1) r.x1 = clip->x1;
 		if (clip->y1 < r.y1) r.y1 = clip->y1;
-		/* no point trying to draw 0-width/height boxes */
-		if (r.x0 == r.x1 || r.y0 == r.y1)
+		/* Nothing to do for invalid rectangles */
+		if (r.x0 >= r.x1 || r.y0 >= r.y1)
 			/* not an error */
 			return ((!plot->group_end) || (plot->group_end()));
 		/* clip to it */
diff --git a/render/html_script.c b/render/html_script.c
index 89d6741..4aa8aff 100644
--- a/render/html_script.c
+++ b/render/html_script.c
@@ -285,12 +285,6 @@ convert_script_sync_cb(hlcache_handle *script,
 	assert(i != parent->scripts_count);
 
 	switch (event->type) {
-	case CONTENT_MSG_LOADING:
-		break;
-
-	case CONTENT_MSG_READY:
-		break;
-
 	case CONTENT_MSG_DONE:
 		LOG(("script %d done '%s'", i,
 				nsurl_access(hlcache_handle_get_url(script))));
@@ -339,10 +333,18 @@ convert_script_sync_cb(hlcache_handle *script,
 
 		break;
 
+	case CONTENT_MSG_LOADING:
+	case CONTENT_MSG_READY:
 	case CONTENT_MSG_STATUS:
+	case CONTENT_MSG_REDIRECT:
+		/* messages content handler will legitamately recive
+		 * but does not need to handle
+		 */
 		break;
 
 	default:
+		/* all other messages are unexpected and fatal */
+		LOG(("Unhandled message type %d", event->type));
 		assert(0);
 	}
 
diff --git a/render/layout.c b/render/layout.c
index 18f67b7..14d06ee 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -44,7 +44,7 @@
 #include "css/css.h"
 #include "css/utils.h"
 #include "content/content_protected.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/scrollbar.h"
 #include "desktop/textarea.h"
 #include "render/box.h"
diff --git a/render/textplain.c b/render/textplain.c
index 89628f9..10cf16a 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -36,7 +36,7 @@
 #include "css/utils.h"
 #include "desktop/browser.h"
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/search.h"
 #include "desktop/selection.h"
diff --git a/resources/FatMessages b/resources/FatMessages
index 82c64ce..d25af01 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -2182,11 +2182,13 @@ en.gtk.preferencesProxyType:Proxy type
 en.gtk.preferencesProxyHost:Host
 en.gtk.preferencesProxyUsername:Username
 en.gtk.preferencesProxyPassword:Password
+en.gtk.preferencesProxyNoproxy:No Proxy For
 en.gtk.preferencesProxyTypeTooltip:The type of HTTP proxy server.
 en.gtk.preferencesProxyHostTooltip:Host name of your proxy server.
 en.gtk.preferencesProxyPortTooltip:Port number to connect to on proxy server.
-en.gtk.preferencesProxyUsernameTooltip:Username to access the proxy
-en.gtk.preferencesProxyPasswordTooltip:Password to access the proxy
+en.gtk.preferencesProxyUsernameTooltip:Username to access the proxy.
+en.gtk.preferencesProxyPasswordTooltip:Password to access the proxy.
+en.gtk.preferencesProxyNoproxyTooltip:Comma separated list of host names that should not be proxied.
 en.gtk.preferencesFetching:<b>Fetching</b>
 en.gtk.preferencesFetchingMax:Maximum fetchers
 en.gtk.preferencesFetchingPerhost:Fetches per host
diff --git a/riscos/Makefile.target b/riscos/Makefile.target
index faefa41..e73a5a3 100644
--- a/riscos/Makefile.target
+++ b/riscos/Makefile.target
@@ -73,7 +73,7 @@ S_RISCOS := 401login.c assert.c bitmap.c buffer.c cookies.c configure.c	\
 	global_history.c gui.c help.c history.c hotlist.c iconbar.c	\
 	image.c menus.c message.c palettes.c plotters.c			\
 	print.c query.c save.c save_draw.c save_pdf.c schedule.c	\
-	search.c searchweb.c sslcert.c system_colour.c textarea.c	\
+	search.c searchweb.c sslcert.c textarea.c	\
 	textselection.c theme.c theme_install.c thumbnail.c toolbar.c	\
 	treeview.c ucstables.c uri.c url_complete.c url_protocol.c	\
 	url_suggest.c wimp.c wimp_event.c window.c			\
diff --git a/riscos/bitmap.c b/riscos/bitmap.c
index d783682..0af01c9 100644
--- a/riscos/bitmap.c
+++ b/riscos/bitmap.c
@@ -39,7 +39,7 @@
 #include "image/bitmap.h"
 #include "riscos/bitmap.h"
 #include "riscos/image.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/palettes.h"
 #include "riscos/content-handlers/sprite.h"
 #include "riscos/tinct.h"
diff --git a/riscos/buffer.c b/riscos/buffer.c
index 6eec8bf..56c2458 100644
--- a/riscos/buffer.c
+++ b/riscos/buffer.c
@@ -27,7 +27,7 @@
 #include "oslib/wimpreadsysinfo.h"
 #include "riscos/buffer.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/tinct.h"
 #include "riscos/wimp.h"
 #include "riscos/wimputils.h"
@@ -274,7 +274,7 @@ void ro_gui_buffer_close(void)
 		_swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
 				(char *)(buffer + 1),
 				clipping.x0, clipping.y0,
-				nsoption_int(fg_plot_style));
+				nsoption_int(plot_fg_quality));
 	else
 		xosspriteop_put_sprite_user_coords(osspriteop_PTR,
 			buffer, (osspriteop_id)(buffer + 1),
diff --git a/riscos/configure/con_cache.c b/riscos/configure/con_cache.c
index cd21123..6e402fe 100644
--- a/riscos/configure/con_cache.c
+++ b/riscos/configure/con_cache.c
@@ -18,7 +18,7 @@
 
 #include <stdbool.h>
 #include "oslib/hourglass.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
 #include "riscos/wimp.h"
diff --git a/riscos/configure/con_connect.c b/riscos/configure/con_connect.c
index c47e904..d9919d0 100644
--- a/riscos/configure/con_connect.c
+++ b/riscos/configure/con_connect.c
@@ -20,7 +20,7 @@
 #include "swis.h"
 #include "oslib/osspriteop.h"
 #include "oslib/wimp.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/configure/configure.h"
 #include "riscos/dialog.h"
 #include "riscos/menus.h"
diff --git a/riscos/configure/con_content.c b/riscos/configure/con_content.c
index 81537bc..d4f3e46 100644
--- a/riscos/configure/con_content.c
+++ b/riscos/configure/con_content.c
@@ -17,7 +17,7 @@
  */
 
 #include <stdbool.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
 #include "riscos/wimp.h"
@@ -44,7 +44,7 @@ bool ro_gui_options_content_initialise(wimp_w w)
 {
 	/* set the current values */
 	ro_gui_set_icon_selected_state(w, CONTENT_BLOCK_ADVERTISEMENTS,
-                                       nsoption_bool(block_ads));
+                                       nsoption_bool(block_advertisements));
 	ro_gui_set_icon_selected_state(w, CONTENT_BLOCK_POPUPS,
                                        nsoption_bool(block_popups));
 	ro_gui_set_icon_selected_state(w, CONTENT_NO_PLUGINS,
@@ -88,7 +88,7 @@ void ro_gui_options_content_default(wimp_pointer *pointer)
 
 bool ro_gui_options_content_ok(wimp_w w)
 {
-	nsoption_set_bool(block_ads,
+	nsoption_set_bool(block_advertisements,
 			  ro_gui_get_icon_selected_state(w, CONTENT_BLOCK_ADVERTISEMENTS));
 
 	nsoption_set_bool(block_popups,
diff --git a/riscos/configure/con_fonts.c b/riscos/configure/con_fonts.c
index 0bd13ce..6261155 100644
--- a/riscos/configure/con_fonts.c
+++ b/riscos/configure/con_fonts.c
@@ -18,7 +18,7 @@
 
 #include <stdbool.h>
 #include "css/css.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plot_style.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
diff --git a/riscos/configure/con_home.c b/riscos/configure/con_home.c
index 9e966b9..6f7d010 100644
--- a/riscos/configure/con_home.c
+++ b/riscos/configure/con_home.c
@@ -17,7 +17,7 @@
  */
 
 #include <stdbool.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
 #include "riscos/menus.h"
diff --git a/riscos/configure/con_image.c b/riscos/configure/con_image.c
index 8617e6d..4982423 100644
--- a/riscos/configure/con_image.c
+++ b/riscos/configure/con_image.c
@@ -20,7 +20,7 @@
 #include "swis.h"
 #include "oslib/osspriteop.h"
 #include "oslib/wimp.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/configure/configure.h"
 #include "riscos/dialog.h"
 #include "riscos/menus.h"
@@ -77,11 +77,11 @@ bool ro_gui_options_image_initialise(wimp_w w)
 
 	/* set the current values */
 	for (i = 0; (i < 4); i++) {
-		if ((unsigned int)nsoption_int(fg_plot_style) == tinct_options[i])
+		if ((unsigned int)nsoption_int(plot_fg_quality) == tinct_options[i])
 			ro_gui_set_icon_string(w, IMAGE_FOREGROUND_FIELD,
 					image_quality_menu->entries[i].
 						data.indirected_text.text, true);
-		if ((unsigned int)nsoption_int(bg_plot_style) == tinct_options[i])
+		if ((unsigned int)nsoption_int(plot_bg_quality) == tinct_options[i])
 			ro_gui_set_icon_string(w, IMAGE_BACKGROUND_FIELD,
 					image_quality_menu->entries[i].
 						data.indirected_text.text, true);
@@ -252,8 +252,8 @@ void ro_gui_options_update_shading(wimp_w w)
 bool ro_gui_options_image_ok(wimp_w w)
 {
 	ro_gui_options_image_read(w, 
-				  (unsigned int *)&nsoption_int(bg_plot_style),
-				  (unsigned int *)&nsoption_int(fg_plot_style));
+				  (unsigned int *)&nsoption_int(plot_bg_quality),
+				  (unsigned int *)&nsoption_int(plot_fg_quality));
 
 	nsoption_set_int(minimum_gif_delay,
 			 ro_gui_get_icon_decimal(w, IMAGE_SPEED_FIELD, 2));
diff --git a/riscos/configure/con_inter.c b/riscos/configure/con_inter.c
index be2114b..2af5e3a 100644
--- a/riscos/configure/con_inter.c
+++ b/riscos/configure/con_inter.c
@@ -19,7 +19,7 @@
 #include <stdbool.h>
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/wimp.h"
 #include "riscos/wimp_event.h"
 #include "riscos/configure.h"
diff --git a/riscos/configure/con_language.c b/riscos/configure/con_language.c
index be40b1c..7e483b5 100644
--- a/riscos/configure/con_language.c
+++ b/riscos/configure/con_language.c
@@ -18,7 +18,7 @@
  */
 
 #include <stdbool.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
 #include "riscos/menus.h"
diff --git a/riscos/configure/con_memory.c b/riscos/configure/con_memory.c
index 5bf8905..2736849 100644
--- a/riscos/configure/con_memory.c
+++ b/riscos/configure/con_memory.c
@@ -17,7 +17,7 @@
  */
 
 #include <stdbool.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/bitmap.h"
 #include "riscos/wimp.h"
 #include "riscos/wimp_event.h"
diff --git a/riscos/configure/con_secure.c b/riscos/configure/con_secure.c
index 568a03d..75e2bc7 100644
--- a/riscos/configure/con_secure.c
+++ b/riscos/configure/con_secure.c
@@ -17,7 +17,7 @@
  */
 
 #include <stdbool.h>
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
 #include "riscos/wimp.h"
diff --git a/riscos/configure/con_theme.c b/riscos/configure/con_theme.c
index b41484b..c4d605c 100644
--- a/riscos/configure/con_theme.c
+++ b/riscos/configure/con_theme.c
@@ -23,7 +23,7 @@
 #include "oslib/wimp.h"
 #include "oslib/wimpspriteop.h"
 #include "utils/config.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/configure/configure.h"
 #include "riscos/configure.h"
 #include "riscos/dialog.h"
diff --git a/riscos/cookies.c b/riscos/cookies.c
index 347b43d..8fb4594 100644
--- a/riscos/cookies.c
+++ b/riscos/cookies.c
@@ -35,7 +35,7 @@
 #include "riscos/cookies.h"
 #include "riscos/dialog.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/toolbar.h"
 #include "riscos/treeview.h"
 #include "riscos/wimp.h"
diff --git a/riscos/dialog.c b/riscos/dialog.c
index 5e4bbbf..0726cb3 100644
--- a/riscos/dialog.c
+++ b/riscos/dialog.c
@@ -41,7 +41,7 @@
 #include "riscos/gui.h"
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/sslcert.h"
 #include "riscos/toolbar.h"
@@ -664,7 +664,7 @@ void ro_gui_dialog_close_persistent(wimp_w parent) {
 
 void ro_gui_save_options(void)
 {
-	nsoption_write("<NetSurf$ChoicesSave>");
+	nsoption_write("<NetSurf$ChoicesSave>", NULL, NULL);
 }
 
 bool ro_gui_dialog_zoom_apply(wimp_w w) {
diff --git a/riscos/download.c b/riscos/download.c
index 233d193..089714c 100644
--- a/riscos/download.c
+++ b/riscos/download.c
@@ -44,7 +44,7 @@
 #include "desktop/gui.h"
 #include "desktop/netsurf.h"
 #include "riscos/dialog.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/query.h"
 #include "riscos/wimp.h"
diff --git a/riscos/font.c b/riscos/font.c
index b949a57..68ee6b6 100644
--- a/riscos/font.c
+++ b/riscos/font.c
@@ -31,7 +31,7 @@
 #include "css/utils.h"
 #include "render/font.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/utils.h"
diff --git a/riscos/global_history.c b/riscos/global_history.c
index ca51b72..8eeb924 100644
--- a/riscos/global_history.c
+++ b/riscos/global_history.c
@@ -36,7 +36,7 @@
 #include "riscos/global_history.h"
 #include "riscos/gui.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/toolbar.h"
 #include "riscos/treeview.h"
diff --git a/riscos/gui.c b/riscos/gui.c
index 53f281d..e409fbb 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -60,7 +60,7 @@
 #include "desktop/history_global_core.h"
 #include "desktop/hotlist.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/save_complete.h"
 #include "desktop/sslcert.h"
 #include "desktop/tree.h"
@@ -84,7 +84,6 @@
 #include "riscos/save.h"
 #include "riscos/sslcert.h"
 #include "riscos/content-handlers/sprite.h"
-#include "riscos/system_colour.h"
 #include "riscos/textselection.h"
 #include "riscos/theme.h"
 #include "riscos/toolbar.h"
@@ -328,45 +327,89 @@ nsurl *gui_get_resource_url(const char *path)
 	return url;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * set option from wimp
+ */
+static nserror
+set_colour_from_wimp(struct nsoption_s *opts,
+                   wimp_colour wimp,
+                   enum nsoption_e option,
+                   colour def_colour)
+{
+	os_error *error;
+	os_PALETTE(20) palette;
+
+	error = xwimp_read_true_palette((os_palette *) &palette);
+	if (error != NULL) {
+		LOG(("xwimp_read_palette: 0x%x: %s",
+		     error->errnum, error->errmess));
+	} else {
+		/* entries are in B0G0R0LL */
+		def_colour = palette.entries[wimp] >> 8;
+	}
+
+	opts[option].value.c = def_colour;
+
+	return NSERROR_OK;
+}
+
+/**
+ * Set option defaults for riscos frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ *
+ * @TODO -- The wimp_COLOUR_... values here map the colour definitions
+ *          to parts of the RISC OS desktop palette.  In places this
+ *          is fairly arbitrary, and could probably do with
+ *          re-checking.
+ *
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
 	/* Set defaults for absent option strings */
-	nsoption_setnull_charp(theme, strdup("Aletheia"));
-	nsoption_setnull_charp(toolbar_browser, strdup("0123|58|9"));
-	nsoption_setnull_charp(toolbar_hotlist, strdup("40|12|3"));
-	nsoption_setnull_charp(toolbar_history, strdup("0|12|3"));
-	nsoption_setnull_charp(toolbar_cookies, strdup("0|12"));
 	nsoption_setnull_charp(ca_bundle, strdup("NetSurf:Resources.ca-bundle"));
 	nsoption_setnull_charp(cookie_file, strdup("NetSurf:Cookies"));
 	nsoption_setnull_charp(cookie_jar, strdup(CHOICES_PREFIX "Cookies"));
-	nsoption_setnull_charp(url_path, strdup("NetSurf:URL"));
-	nsoption_setnull_charp(url_save, strdup(CHOICES_PREFIX "URL"));
-	nsoption_setnull_charp(hotlist_path, strdup("NetSurf:Hotlist"));
-	nsoption_setnull_charp(hotlist_save, strdup(CHOICES_PREFIX "Hotlist"));
-	nsoption_setnull_charp(recent_path, strdup("NetSurf:Recent"));
-	nsoption_setnull_charp(recent_save, strdup(CHOICES_PREFIX "Recent"));
-	nsoption_setnull_charp(theme_path, strdup("NetSurf:Themes"));
-	nsoption_setnull_charp(theme_save, strdup(CHOICES_PREFIX "Themes"));
-
-	if (nsoption_charp(theme) == NULL ||
-			nsoption_charp(toolbar_browser) == NULL ||
-			nsoption_charp(toolbar_hotlist) == NULL ||
-			nsoption_charp(toolbar_history) == NULL ||
-			nsoption_charp(toolbar_cookies) == NULL ||
-			nsoption_charp(ca_bundle) == NULL ||
-			nsoption_charp(cookie_file) == NULL ||
-			nsoption_charp(cookie_jar) == NULL ||
-			nsoption_charp(url_path) == NULL ||
-			nsoption_charp(url_save) == NULL ||
-			nsoption_charp(hotlist_path) == NULL ||
-			nsoption_charp(hotlist_save) == NULL ||
-			nsoption_charp(recent_path) == NULL ||
-			nsoption_charp(recent_save) == NULL ||
-			nsoption_charp(theme_path) == NULL ||
-			nsoption_charp(theme_save) == NULL) {
-		die("Failed initialising string options");
-	}
+
+	if (nsoption_charp(ca_bundle) == NULL ||
+	    nsoption_charp(cookie_file) == NULL ||
+	    nsoption_charp(cookie_jar) == NULL) {
+		LOG(("Failed initialising string options"));
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	/* set default system colours for riscos ui */
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_ActiveBorder, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_CREAM, NSOPTION_sys_colour_ActiveCaption, 0x00dddddd);
+	set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_AppWorkspace, 0x00eeeeee);
+	set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_Background, 0x00aa0000);/* \TODO -- Check */
+	set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_ButtonFace, 0x00aaaaaa);
+	set_colour_from_wimp(defaults, wimp_COLOUR_DARK_GREY, NSOPTION_sys_colour_ButtonHighlight, 0x00cccccc);/* \TODO -- Check */
+	set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ButtonShadow, 0x00bbbbbb);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_ButtonText, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_CaptionText, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_MID_LIGHT_GREY, NSOPTION_sys_colour_GrayText, 0x00777777);/* \TODO -- Check */
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_Highlight, 0x00ee0000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_HighlightText, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InactiveBorder, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_LIGHT_GREY, NSOPTION_sys_colour_InactiveCaption, 0x00ffffff);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InactiveCaptionText, 0x00cccccc);
+	set_colour_from_wimp(defaults, wimp_COLOUR_CREAM, NSOPTION_sys_colour_InfoBackground, 0x00aaaaaa);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InfoText, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_Menu, 0x00aaaaaa);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_MenuText, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_LIGHT_GREY, NSOPTION_sys_colour_Scrollbar, 0x00aaaaaa);/* \TODO -- Check */
+	set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ThreeDDarkShadow, 0x00555555);
+	set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_ThreeDFace, 0x00dddddd);
+	set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_ThreeDHighlight, 0x00aaaaaa);
+	set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_ThreeDLightShadow, 0x00999999);
+	set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ThreeDShadow, 0x00777777);
+	set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_Window, 0x00aaaaaa);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_WindowFrame, 0x00000000);
+	set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_WindowText, 0x00000000);
+
+	return NSERROR_OK;
 }
 
 /**
@@ -799,6 +842,17 @@ static void gui_init2(int argc, char** argv)
 	free(url);
 }
 
+/** 
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+        /* set log stream to be non-buffering */
+	setbuf(fptr, NULL);
+
+	return true;
+}
+
 /** Normal entry point from OS */
 int main(int argc, char** argv)
 {
@@ -808,8 +862,7 @@ int main(int argc, char** argv)
 	os_var_type type;
 	int used = -1;  /* slightly better with older OSLib versions */
 	os_error *error;
-
-	setbuf(stderr, NULL);
+	nserror ret;
 
 	/* Consult NetSurf$Logging environment variable to decide if logging
 	 * is required. */
@@ -828,25 +881,42 @@ int main(int argc, char** argv)
 		}
 	}
 
-	/* Pass a NULL pointer for Messages path, because until the Choices
-	 * are loaded in netsurf_init, we don't know the Messages path. */
-	netsurf_init(&argc, &argv, "NetSurf:Choices", NULL);
+	/* initialise logging. Not fatal if it fails but not much we
+	 * can do about it either.
+	 */
+	nslog_init(nslog_stream_configure, &argc, argv);
 
-	artworks_init();
-	draw_init();
-	sprite_init();
+	/* user options setup */
+	ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	nsoption_read("NetSurf:Choices", NULL);
+	nsoption_commandline(&argc, argv, NULL);
 
 	/* Choose the interface language to use */
 	ro_gui_choose_language();
 
-	/* Load in our language-specific Messages */
-	if ((length = snprintf(path, sizeof(path),
-			"NetSurf:Resources.%s.Messages",
-			nsoption_charp(language))) < 0 || length >= (int)sizeof(path))
+	/* select language-specific Messages */
+	if (((length = snprintf(path,
+				sizeof(path),
+			       "NetSurf:Resources.%s.Messages",
+				nsoption_charp(language))) < 0) || 
+	    (length >= (int)sizeof(path))) {
 		die("Failed to locate Messages resource.");
-	/* We disabled core Messages load, so have to load them here */
-	messages_load(path);
-	/* Also load some extra RISC OS specific Messages */
+	}
+
+	/* common initialisation */
+	ret = netsurf_init(path);
+	if (ret != NSERROR_OK) {
+		die("NetSurf failed to initialise");
+	}
+
+	artworks_init();
+	draw_init();
+	sprite_init();
+
+	/* Load some extra RISC OS specific Messages */
 	messages_load("NetSurf:Resources.LangNames");
 
 	gui_init(argc, argv);
@@ -898,7 +968,7 @@ void ro_gui_signal(int sig)
 
 	xhourglass_on();
 	xhourglass_colours(0x0000ffff, 0x000000ff, &old_sand, &old_glass);
-	nsoption_dump(stderr);
+	nsoption_dump(stderr, NULL);
 	/*rufl_dump_state();*/
 
 #ifndef __ELF__
@@ -1392,11 +1462,9 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message)
 		case message_MODE_CHANGE:
 			ro_gui_get_screen_properties();
 			rufl_invalidate_cache();
-			ro_gui_system_colour_update();
 			break;
 
 		case message_PALETTE_CHANGE:
-			ro_gui_system_colour_update();
 			break;
 
 		case message_FONT_CHANGED:
diff --git a/riscos/help.c b/riscos/help.c
index ae2a2af..14d34af 100644
--- a/riscos/help.c
+++ b/riscos/help.c
@@ -35,7 +35,7 @@
 #include "riscos/help.h"
 #include "riscos/iconbar.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/treeview.h"
 #include "riscos/wimp.h"
 #include "riscos/wimp_event.h"
diff --git a/riscos/history.c b/riscos/history.c
index 8a3b562..65ae847 100644
--- a/riscos/history.c
+++ b/riscos/history.c
@@ -31,7 +31,7 @@
 #include "desktop/plotters.h"
 #include "riscos/dialog.h"
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/gui.h"
 #include "riscos/wimp.h"
 #include "riscos/wimp_event.h"
diff --git a/riscos/hotlist.c b/riscos/hotlist.c
index 53212c1..b8449cd 100644
--- a/riscos/hotlist.c
+++ b/riscos/hotlist.c
@@ -39,7 +39,7 @@
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
 #include "riscos/message.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/toolbar.h"
 #include "riscos/treeview.h"
diff --git a/riscos/iconbar.c b/riscos/iconbar.c
index 6c7996a..f6c0942 100644
--- a/riscos/iconbar.c
+++ b/riscos/iconbar.c
@@ -38,7 +38,7 @@
 #include "riscos/hotlist.h"
 #include "riscos/iconbar.h"
 #include "desktop/browser.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/wimp_event.h"
 #include "utils/log.h"
 #include "utils/messages.h"
diff --git a/riscos/image.c b/riscos/image.c
index 3d4f28b..56feb2b 100644
--- a/riscos/image.c
+++ b/riscos/image.c
@@ -22,7 +22,7 @@
 #include "oslib/osspriteop.h"
 #include "riscos/image.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/tinct.h"
 #include "utils/log.h"
 #include "utils/utils.h"
@@ -69,8 +69,8 @@ bool image_redraw(osspriteop_area *area, int x, int y, int req_width,
 	req_height *= 2;
 	width *= 2;
 	height *= 2;
-	tinct_options = background ? nsoption_int(bg_plot_style) :
-		nsoption_int(fg_plot_style);
+	tinct_options = background ? nsoption_int(plot_bg_quality) :
+		nsoption_int(plot_fg_quality);
 	switch (type) {
 		case IMAGE_PLOT_TINCT_ALPHA:
 			return image_redraw_tinct(header, x, y,
diff --git a/riscos/menus.c b/riscos/menus.c
index 5c80fd9..aaec8cf 100644
--- a/riscos/menus.c
+++ b/riscos/menus.c
@@ -50,7 +50,7 @@
 #include "riscos/help.h"
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/tinct.h"
 #include "riscos/toolbar.h"
diff --git a/riscos/options.h b/riscos/options.h
index 62bfcf2..3d4567f 100644
--- a/riscos/options.h
+++ b/riscos/options.h
@@ -1,7 +1,5 @@
 /*
- * Copyright 2003 Phil Mellor <monkeyson at users.sourceforge.net>
- * Copyright 2004 James Bursa <bursa at users.sourceforge.net>
- * Copyright 2004 Richard Wilson <not_ginger_matt at users.sourceforge.net>
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -22,131 +20,50 @@
  * RISC OS specific options.
  */
 
-#include "riscos/tinct.h"
-
-#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
-#error "Frontend options header cannot be included directly"
-#endif
-
 #ifndef _NETSURF_RISCOS_OPTIONS_H_
 #define _NETSURF_RISCOS_OPTIONS_H_
 
-#define NSOPTION_EXTRA_DEFINE				\
-	bool use_mouse_gestures;			\
-	bool allow_text_selection;			\
-	char *theme;					\
-	char *language;					\
-	int fg_plot_style; /* tinct flagword */			\
-	int bg_plot_style; /* tinct flagword */			\
-	bool history_tooltip;					\
-	bool toolbar_show_buttons;				\
-	bool toolbar_show_address;				\
-	bool toolbar_show_throbber;				\
-	char *toolbar_browser;					\
-	char *toolbar_hotlist;					\
-	char *toolbar_history;					\
-	char *toolbar_cookies;					\
-	bool window_stagger;					\
-	bool window_size_clone;					\
-	bool buffer_animations;					\
-	bool buffer_everything;					\
-	bool open_browser_at_startup;				\
-	bool no_plugins;					\
-	bool block_popups;					\
-	int image_memory_direct; /* -1 means auto-detect */	\
-	int image_memory_compressed; /* -1 means auto-detect */	\
-	bool strip_extensions;					\
-	bool confirm_overwrite;					\
-	char *url_path;						\
-	char *url_save;						\
-	char *hotlist_path;					\
-	char *hotlist_save;					\
-	char *recent_path;					\
-	char *recent_save;					\
-	char *theme_path;					\
-	char *theme_save;					\
-	bool thumbnail_iconise;					\
-	bool interactive_help;					\
-	bool external_hotlists;					\
-	char *external_hotlist_app
-
+#include "riscos/tinct.h"
 
-#define NSOPTION_EXTRA_DEFAULTS			\
-	.use_mouse_gestures = false,		\
-	.allow_text_selection = true,		\
-	.theme = NULL,				\
-	.language = NULL,			\
-	.fg_plot_style = tinct_ERROR_DIFFUSE,	\
-	.bg_plot_style = tinct_DITHER,		\
-	.history_tooltip = true,		\
-	.toolbar_show_buttons = true,		\
-	.toolbar_show_address = true,		\
-	.toolbar_show_throbber = true,		\
-	.toolbar_browser = NULL,		\
-	.toolbar_hotlist = NULL,		\
-	.toolbar_history = NULL,		\
-	.toolbar_cookies = NULL,		\
-	.window_stagger = true,			\
-	.window_size_clone = true,		\
-	.buffer_animations = true,		\
-	.buffer_everything = true,		\
-	.open_browser_at_startup = false,	\
-	.no_plugins = false,			\
-	.block_popups = false,			\
-	.image_memory_direct = -1,		\
-	.image_memory_compressed = -1,		\
-	.strip_extensions = true,		\
-	.confirm_overwrite = true,		\
-	.url_path = NULL,			\
-	.url_save = NULL,			\
-	.hotlist_path = NULL,			\
-	.hotlist_save = NULL,			\
-	.recent_path = NULL,			\
-	.recent_save = NULL,			\
-	.theme_path = NULL,			\
-	.theme_save = NULL,			\
-	.thumbnail_iconise = true,		\
-	.interactive_help = true,		\
-	.external_hotlists = false,		\
-	.external_hotlist_app = NULL
+/* setup longer default reflow time */
+#define DEFAULT_REFLOW_PERIOD 100 /* time in cs */
 
-#define NSOPTION_EXTRA_TABLE \
-{ "use_mouse_gestures",     OPTION_BOOL,    &nsoptions.use_mouse_gestures },\
-{ "allow_text_selection",   OPTION_BOOL,    &nsoptions.allow_text_selection },\
-{ "theme",                  OPTION_STRING,  &nsoptions.theme },\
-{ "language",               OPTION_STRING,  &nsoptions.language },\
-{ "plot_fg_quality",        OPTION_INTEGER, &nsoptions.fg_plot_style },\
-{ "plot_bg_quality",        OPTION_INTEGER, &nsoptions.bg_plot_style },\
-{ "history_tooltip",        OPTION_BOOL,    &nsoptions.history_tooltip }, \
-{ "toolbar_show_buttons",   OPTION_BOOL,    &nsoptions.toolbar_show_buttons }, \
-{ "toolbar_show_address",   OPTION_BOOL,    &nsoptions.toolbar_show_address }, \
-{ "toolbar_show_throbber",  OPTION_BOOL,    &nsoptions.toolbar_show_throbber }, \
-{ "toolbar_browser",	    OPTION_STRING,  &nsoptions.toolbar_browser }, \
-{ "toolbar_hotlist",	    OPTION_STRING,  &nsoptions.toolbar_hotlist }, \
-{ "toolbar_history",	    OPTION_STRING,  &nsoptions.toolbar_history }, \
-{ "toolbar_cookies",	    OPTION_STRING,  &nsoptions.toolbar_cookies }, \
-{ "window_stagger",         OPTION_BOOL,    &nsoptions.window_stagger }, \
-{ "window_size_clone",      OPTION_BOOL,    &nsoptions.window_size_clone }, \
-{ "buffer_animations",      OPTION_BOOL,    &nsoptions.buffer_animations }, \
-{ "buffer_everything",      OPTION_BOOL,    &nsoptions.buffer_everything }, \
-{ "open_browser_at_startup",OPTION_BOOL,    &nsoptions.open_browser_at_startup }, \
-{ "no_plugins",             OPTION_BOOL,    &nsoptions.no_plugins }, \
-{ "block_popups",           OPTION_BOOL,    &nsoptions.block_popups }, \
-{ "image_memory_direct",    OPTION_INTEGER, &nsoptions.image_memory_direct }, \
-{ "image_memory_compressed",OPTION_INTEGER, &nsoptions.image_memory_compressed }, \
-{ "strip_extensions",       OPTION_BOOL,    &nsoptions.strip_extensions }, \
-{ "confirm_overwrite",      OPTION_BOOL,    &nsoptions.confirm_overwrite }, \
-{ "url_path",               OPTION_STRING,  &nsoptions.url_path }, \
-{ "url_save",               OPTION_STRING,  &nsoptions.url_save }, \
-{ "hotlist_path",           OPTION_STRING,  &nsoptions.hotlist_path }, \
-{ "hotlist_save",           OPTION_STRING,  &nsoptions.hotlist_save }, \
-{ "recent_path",            OPTION_STRING,  &nsoptions.recent_path }, \
-{ "recent_save",            OPTION_STRING,  &nsoptions.recent_save }, \
-{ "theme_path",             OPTION_STRING,  &nsoptions.theme_path }, \
-{ "theme_save",             OPTION_STRING,  &nsoptions.theme_save }, \
-{ "thumbnail_iconise",      OPTION_BOOL,    &nsoptions.thumbnail_iconise }, \
-{ "interactive_help",       OPTION_BOOL,    &nsoptions.interactive_help }, \
-{ "external_hotlists",      OPTION_BOOL,    &nsoptions.external_hotlists }, \
-{ "external_hotlist_app",   OPTION_STRING,  &nsoptions.external_hotlist_app }
+#define CHOICES_PREFIX "<Choices$Write>.WWW.NetSurf."
 
 #endif
+
+NSOPTION_STRING(theme, "Aletheia")
+NSOPTION_STRING(language, NULL)
+NSOPTION_INTEGER(plot_fg_quality, tinct_ERROR_DIFFUSE)
+NSOPTION_INTEGER(plot_bg_quality, tinct_DITHER)
+NSOPTION_BOOL(history_tooltip, true)
+NSOPTION_BOOL(toolbar_show_buttons, true)
+NSOPTION_BOOL(toolbar_show_address, true)
+NSOPTION_BOOL(toolbar_show_throbber, true)
+NSOPTION_STRING(toolbar_browser, "0123|58|9")
+NSOPTION_STRING(toolbar_hotlist, "40|12|3")
+NSOPTION_STRING(toolbar_history, "0|12|3")
+NSOPTION_STRING(toolbar_cookies, "0|12")
+NSOPTION_BOOL(window_stagger, true)
+NSOPTION_BOOL(window_size_clone, true)
+NSOPTION_BOOL(buffer_animations, true)
+NSOPTION_BOOL(buffer_everything, true)
+NSOPTION_BOOL(open_browser_at_startup, false)
+NSOPTION_BOOL(no_plugins, false)
+NSOPTION_BOOL(block_popups, false)
+NSOPTION_INTEGER(image_memory_direct, -1)
+NSOPTION_INTEGER(image_memory_compressed, -1)
+NSOPTION_BOOL(strip_extensions, false)
+NSOPTION_BOOL(confirm_overwrite, true)
+NSOPTION_STRING(url_path, "NetSurf:URL")
+NSOPTION_STRING(url_save, CHOICES_PREFIX "URL")
+NSOPTION_STRING(hotlist_path, "NetSurf:Hotlist")
+NSOPTION_STRING(hotlist_save, CHOICES_PREFIX "Hotlist")
+NSOPTION_STRING(recent_path, "NetSurf:Recent")
+NSOPTION_STRING(recent_save, CHOICES_PREFIX "Recent")
+NSOPTION_STRING(theme_path, "NetSurf:Themes")
+NSOPTION_STRING(theme_save, CHOICES_PREFIX "Themes")
+NSOPTION_BOOL(thumbnail_iconise, true)
+NSOPTION_BOOL(interactive_help, true)
+NSOPTION_BOOL(external_hotlists, false)
+NSOPTION_STRING(external_hotlist_app, NULL)
diff --git a/riscos/print.c b/riscos/print.c
index 05eb8fd..0df77ef 100644
--- a/riscos/print.c
+++ b/riscos/print.c
@@ -33,7 +33,7 @@
 #include "content/content.h"
 #include "content/hlcache.h"
 #include "desktop/browser_private.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "riscos/dialog.h"
 #include "riscos/menus.h"
diff --git a/riscos/save.c b/riscos/save.c
index 7ccbfb1..390165d 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -49,7 +49,7 @@
 #include "riscos/gui.h"
 #include "riscos/menus.h"
 #include "riscos/message.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/query.h"
 #include "riscos/save.h"
 #include "riscos/save_draw.h"
diff --git a/riscos/system_colour.c b/riscos/system_colour.c
deleted file mode 100644
index 104aa3b..0000000
--- a/riscos/system_colour.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "oslib/os.h"
-#include "oslib/wimp.h"
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-#include "riscos/system_colour.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	wimp_colour system_colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-/* \TODO -- The wimp_COLOUR_... values in the table below map the colour
- *          definitions to parts of the RISC OS desktop palette.  In places
- *          this is fairly arbitrary, and could probably do with re-checking.
- */
-
-static struct gui_system_colour_ctx colour_list[] = {
-	{
-		"ActiveBorder",
-		SLEN("ActiveBorder"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_ActiveBorder),
-		NULL
-	}, {
-		"ActiveCaption",
-		SLEN("ActiveCaption"),
-		0xffdddddd,
-		wimp_COLOUR_CREAM,
-		&nsoption_colour(sys_colour_ActiveCaption),
-		NULL
-	}, {
-		"AppWorkspace",
-		SLEN("AppWorkspace"),
-		0xffeeeeee,
-		wimp_COLOUR_VERY_LIGHT_GREY,
-		&nsoption_colour(sys_colour_AppWorkspace),
-		NULL
-	}, {
-		"Background",
-		SLEN("Background"),
-		0xff0000aa,
-		wimp_COLOUR_VERY_LIGHT_GREY, /* \TODO -- Check */
-		&nsoption_colour(sys_colour_Background),
-		NULL
-	}, {
-		"ButtonFace",
-		SLEN("ButtonFace"),
-		0xffaaaaaa,
-		wimp_COLOUR_VERY_LIGHT_GREY,
-		&nsoption_colour(sys_colour_ButtonFace),
-		NULL
-	}, {
-		"ButtonHighlight",
-		SLEN("ButtonHighlight"),
-		0xffdddddd,
-		wimp_COLOUR_DARK_GREY, /* \TODO -- Check */
-		&nsoption_colour(sys_colour_ButtonHighlight),
-		NULL
-	}, {
-		"ButtonShadow",
-		SLEN("ButtonShadow"),
-		0xffbbbbbb,
-		wimp_COLOUR_MID_DARK_GREY,
-		&nsoption_colour(sys_colour_ButtonShadow),
-		NULL
-	}, {
-		"ButtonText",
-		SLEN("ButtonText"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_ButtonText),
-		NULL
-	}, {
-		"CaptionText",
-		SLEN("CaptionText"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_CaptionText),
-		NULL
-	}, {
-		"GrayText",
-		SLEN("GrayText"),
-		0xffcccccc,
-		wimp_COLOUR_MID_LIGHT_GREY, /* \TODO -- Check */
-		&nsoption_colour(sys_colour_GrayText),
-		NULL
-	}, {
-		"Highlight",
-		SLEN("Highlight"),
-		0xff0000ee,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_Highlight),
-		NULL
-	}, {
-		"HighlightText",
-		SLEN("HighlightText"),
-		0xff000000,
-		wimp_COLOUR_WHITE,
-		&nsoption_colour(sys_colour_HighlightText),
-		NULL
-	}, {
-		"InactiveBorder",
-		SLEN("InactiveBorder"),
-		0xffffffff,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_InactiveBorder),
-		NULL
-	}, {
-		"InactiveCaption",
-		SLEN("InactiveCaption"),
-		0xffffffff,
-		wimp_COLOUR_LIGHT_GREY,
-		&nsoption_colour(sys_colour_InactiveCaption),
-		NULL
-	}, {
-		"InactiveCaptionText",
-		SLEN("InactiveCaptionText"),
-		0xffcccccc,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_InactiveCaptionText),
-		NULL
-	}, {
-		"InfoBackground",
-		SLEN("InfoBackground"),
-		0xffaaaaaa,
-		wimp_COLOUR_CREAM,
-		&nsoption_colour(sys_colour_InfoBackground),
-		NULL
-	}, {
-		"InfoText",
-		SLEN("InfoText"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_InfoText),
-		NULL
-	}, {
-		"Menu",
-		SLEN("Menu"),
-		0xffaaaaaa,
-		wimp_COLOUR_WHITE,
-		&nsoption_colour(sys_colour_Menu),
-		NULL
-	}, {
-		"MenuText",
-		SLEN("MenuText"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_MenuText),
-		NULL
-	}, {
-		"Scrollbar",
-		SLEN("Scrollbar"),
-		0xffaaaaaa,
-		wimp_COLOUR_LIGHT_GREY, /* \TODO -- Check */
-		&nsoption_colour(sys_colour_Scrollbar),
-		NULL
-	}, {
-		"ThreeDDarkShadow",
-		SLEN("ThreeDDarkShadow"),
-		0xff555555,
-		wimp_COLOUR_MID_DARK_GREY,
-		&nsoption_colour(sys_colour_ThreeDDarkShadow),
-		NULL
-	}, {
-		"ThreeDFace",
-		SLEN("ThreeDFace"),
-		0xffdddddd,
-		wimp_COLOUR_VERY_LIGHT_GREY,
-		&nsoption_colour(sys_colour_ThreeDFace),
-		NULL
-	}, {
-		"ThreeDHighlight",
-		SLEN("ThreeDHighlight"),
-		0xffaaaaaa,
-		wimp_COLOUR_WHITE,
-		&nsoption_colour(sys_colour_ThreeDHighlight),
-		NULL
-	}, {
-		"ThreeDLightShadow",
-		SLEN("ThreeDLightShadow"),
-		0xff999999,
-		wimp_COLOUR_WHITE,
-		&nsoption_colour(sys_colour_ThreeDLightShadow),
-		NULL
-	}, {
-		"ThreeDShadow",
-		SLEN("ThreeDShadow"),
-		0xff777777,
-		wimp_COLOUR_MID_DARK_GREY,
-		&nsoption_colour(sys_colour_ThreeDShadow),
-		NULL
-	}, {
-		"Window",
-		SLEN("Window"),
-		0xffaaaaaa,
-		wimp_COLOUR_VERY_LIGHT_GREY,
-		&nsoption_colour(sys_colour_Window),
-		NULL
-	}, {
-		"WindowFrame",
-		SLEN("WindowFrame"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_WindowFrame),
-		NULL
-	}, {
-		"WindowText",
-		SLEN("WindowText"),
-		0xff000000,
-		wimp_COLOUR_BLACK,
-		&nsoption_colour(sys_colour_WindowText),
-		NULL
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL)
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name,
-				colour_list[ccount].length,
-				&(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour =
-					*(colour_list[ccount].option_colour);
-		}
-	}
-
-	ro_gui_system_colour_update();
-
-	gui_system_colour_pw = colour_list;
-
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name,
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}
-
-	return CSS_INVALID;
-}
-
-
-#define ro_gui_system_colour_convert_os_to_css(os) (0xff000000 | 	\
-		(((os) & 0x0000ff00) << 8) |				\
-		(((os) & 0x00ff0000) >> 8) |				\
-		(((os) & 0xff000000) >> 24))
-
-
-/* This is a exported interface for the RISC OS frontend,
- * documented in riscos/system_colour.h
- */
-
-void ro_gui_system_colour_update(void)
-{
-	os_error	*error;
-	os_PALETTE(20)	palette;
-	unsigned int	ccount;
-
-	error = xwimp_read_palette((os_palette *) &palette);
-	if (error != NULL) {
-		LOG(("xwimp_read_palette: 0x%x: %s",
-				error->errnum, error->errmess));
-		return;
-	}
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) == 0) {
-			colour_list[ccount].colour =
-					ro_gui_system_colour_convert_os_to_css(
-					palette.entries[colour_list[ccount].
-						system_colour]);
-		}
-	}
-}
diff --git a/riscos/system_colour.h b/riscos/system_colour.h
deleted file mode 100644
index a6672e3..0000000
--- a/riscos/system_colour.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2011 Stephen Fryatt <stevef at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling (frontend internal interface)
- */
-
-#ifndef _NETSURF_RISCOS_SYSTEM_COLOUR_H_
-#define _NETSURF_RISCOS_SYSTEM_COLOUR_H_
-
-/**
- * Scan the CSS system colour definitions, and update any that haven't been
- * overridden in NetSurf's options to reflect the current Desktop palette.
- */
-
-void ro_gui_system_colour_update(void);
-
-#endif
-
diff --git a/riscos/theme.c b/riscos/theme.c
index b44493d..f1b7ae2 100644
--- a/riscos/theme.c
+++ b/riscos/theme.c
@@ -44,7 +44,7 @@
 #include "riscos/gui.h"
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/theme.h"
 #include "riscos/treeview.h"
 #include "riscos/wimp.h"
diff --git a/riscos/theme_install.c b/riscos/theme_install.c
index e5d5aaf..0d436dc 100644
--- a/riscos/theme_install.c
+++ b/riscos/theme_install.c
@@ -28,7 +28,7 @@
 #include "desktop/browser.h"
 #include "riscos/dialog.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/theme.h"
 #include "riscos/wimp.h"
 #include "riscos/wimp_event.h"
diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c
index 2a140ce..6686455 100644
--- a/riscos/thumbnail.c
+++ b/riscos/thumbnail.c
@@ -40,7 +40,7 @@
 #include "render/font.h"
 #include "riscos/bitmap.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/oslib_pre7.h"
 #include "riscos/thumbnail.h"
 #include "riscos/tinct.h"
diff --git a/riscos/toolbar.c b/riscos/toolbar.c
index 7e95ce6..d56c6fa 100644
--- a/riscos/toolbar.c
+++ b/riscos/toolbar.c
@@ -49,7 +49,7 @@
 #include "riscos/gui/url_bar.h"
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/save.h"
 #include "riscos/theme.h"
 #include "riscos/toolbar.h"
diff --git a/riscos/url_complete.c b/riscos/url_complete.c
index 990ce42..e26cb65 100644
--- a/riscos/url_complete.c
+++ b/riscos/url_complete.c
@@ -30,7 +30,7 @@
 #include "utils/log.h"
 #include "riscos/global_history.h"
 #include "riscos/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/toolbar.h"
 #include "riscos/url_complete.h"
 #include "riscos/wimp.h"
diff --git a/riscos/window.c b/riscos/window.c
index 295315d..772a0d1 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -69,7 +69,7 @@
 #include "riscos/help.h"
 #include "riscos/hotlist.h"
 #include "riscos/menus.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "riscos/oslib_pre7.h"
 #include "riscos/save.h"
 #include "riscos/content-handlers/sprite.h"
@@ -521,7 +521,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
 
 	/* Add in a toolbar and status bar */
 	g->status_bar = ro_gui_status_bar_create(g->window,
-						 nsoption_int(toolbar_status_width));
+						 nsoption_int(toolbar_status_size));
 	g->toolbar = ro_toolbar_create(NULL, g->window,
 			THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE,
 			&ro_gui_window_toolbar_callbacks, g,
@@ -4712,7 +4712,7 @@ void ro_gui_window_default_options(struct browser_window *bw)
 				  ro_toolbar_get_display_throbber(gui->toolbar));
 	}
 	if (gui->status_bar != NULL)
-		nsoption_set_int(toolbar_status_width,
+		nsoption_set_int(toolbar_status_size,
 				 ro_gui_status_bar_get_width(gui->status_bar));
 }
 
diff --git a/test/Makefile b/test/Makefile
index e61e21f..ecd2b50 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -26,9 +26,12 @@ nsurl_SRCS := utils/log.c utils/nsurl.c test/nsurl.c
 nsurl_CFLAGS := $(shell pkg-config --cflags libwapcaplet)
 nsurl_LDFLAGS := $(shell pkg-config --libs libwapcaplet)
 
+nsoption_SRCS := utils/log.c utils/nsoption.c test/nsoption.c
+nsoption_CFLAGS := -Dnsgtk
+
 .PHONY: all
 
-all: llcache urldbtest nsurl
+all: llcache urldbtest nsurl nsoption
 
 llcache: $(addprefix ../,$(llcache_SRCS))
 	$(CC) $(CFLAGS) $(llcache_CFLAGS) $^ -o $@ $(LDFLAGS) $(llcache_LDFLAGS)
@@ -39,7 +42,10 @@ urldbtest: $(addprefix ../,$(urldbtest_SRCS))
 nsurl: $(addprefix ../,$(nsurl_SRCS))
 	$(CC) $(CFLAGS) $(nsurl_CFLAGS) $^ -o $@ $(LDFLAGS) $(nsurl_LDFLAGS)
 
+nsoption: $(addprefix ../,$(nsoption_SRCS))
+	$(CC) $(CFLAGS) $(nsoption_CFLAGS) $^ -o $@ $(LDFLAGS) $(nsoption_LDFLAGS)
+
 .PHONY: clean
 
 clean:
-	$(RM) llcache urldbtest nsurl
+	$(RM) llcache urldbtest nsurl nsoption
diff --git a/test/data/Choices b/test/data/Choices
new file mode 100644
index 0000000..f4a62af
--- /dev/null
+++ b/test/data/Choices
@@ -0,0 +1,104 @@
+http_proxy:0
+http_proxy_port:8080
+http_proxy_auth:0
+font_size:128
+font_min_size:85
+font_sans:Sans
+font_serif:Serif
+font_mono:Monospace
+font_cursive:Serif
+font_fantasy:Serif
+accept_language:en
+memory_cache_size:12582912
+disc_cache_size:1073741824
+disc_cache_age:28
+block_advertisements:0
+do_not_track:0
+minimum_gif_delay:10
+send_referer:1
+foreground_images:1
+background_images:1
+animate_images:1
+enable_javascript:1
+script_timeout:10
+expire_url:28
+font_default:0
+ca_path:/etc/ssl/certs
+cookie_file:/home/vince/.netsurf/Cookies
+cookie_jar:/home/vince/.netsurf/Cookies
+homepage_url:about:welcome
+search_url_bar:0
+search_provider:0
+url_suggestion:1
+window_x:0
+window_y:0
+window_width:0
+window_height:0
+window_screen_width:0
+window_screen_height:0
+toolbar_status_size:6667
+scale:100
+incremental_reflow:1
+min_reflow_period:25
+core_select_menu:1
+max_fetchers:24
+max_fetchers_per_host:5
+max_cached_fetch_handles:6
+suppress_curl_debug:1
+target_blank:1
+button_2_tab:1
+margin_top:10
+margin_bottom:10
+margin_left:10
+margin_right:10
+export_scale:70
+suppress_images:0
+remove_backgrounds:0
+enable_loosening:1
+enable_PDF_compression:1
+enable_PDF_password:0
+sys_colour_ActiveBorder:000000
+sys_colour_ActiveCaption:000000
+sys_colour_AppWorkspace:000000
+sys_colour_Background:000000
+sys_colour_ButtonFace:000000
+sys_colour_ButtonHighlight:000000
+sys_colour_ButtonShadow:000000
+sys_colour_ButtonText:000000
+sys_colour_CaptionText:000000
+sys_colour_GrayText:000000
+sys_colour_Highlight:000000
+sys_colour_HighlightText:000000
+sys_colour_InactiveBorder:000000
+sys_colour_InactiveCaption:000000
+sys_colour_InactiveCaptionText:000000
+sys_colour_InfoBackground:000000
+sys_colour_InfoText:000000
+sys_colour_Menu:000000
+sys_colour_MenuText:000000
+sys_colour_Scrollbar:000000
+sys_colour_ThreeDDarkShadow:000000
+sys_colour_ThreeDFace:000000
+sys_colour_ThreeDHighlight:000000
+sys_colour_ThreeDLightShadow:000000
+sys_colour_ThreeDShadow:000000
+sys_colour_Window:000000
+sys_colour_WindowFrame:000000
+sys_colour_WindowText:000000
+render_resample:1
+downloads_clear:0
+request_overwrite:1
+downloads_directory:/home/vince
+url_file:/home/vince/.netsurf/URLs
+show_single_tab:1
+button_type:1
+disable_popups:0
+disable_plugins:0
+history_age:0
+hover_urls:0
+focus_new:0
+new_blank:0
+hotlist_path:/home/vince/.netsurf/Hotlist
+source_tab:0
+current_theme:0
+position_tab:0
diff --git a/test/js/core.infinite.html b/test/js/core.infinite.html
new file mode 100644
index 0000000..7e6b8de
--- /dev/null
+++ b/test/js/core.infinite.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Infinite loop</title>
+<link rel="stylesheet" type="text/css" href="tst.css">
+</head>
+<body>
+<h1>Infinite loop</h1>
+<p>Before</p>
+<script>
+
+function bar(x) { return  (x/2) + 1; }
+
+n=1;
+while (n < 3) {
+  n = bar(n);
+
+}
+
+</script>
+</script>
+<p>Afterwards</p>
+</body>
+</html>
diff --git a/test/js/core.recursion.html b/test/js/core.recursion.html
new file mode 100644
index 0000000..6c2206b
--- /dev/null
+++ b/test/js/core.recursion.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+<title>Infinite recursion</title>
+<link rel="stylesheet" type="text/css" href="tst.css">
+</head>
+<body>
+<h1>Infinite recursion</h1>
+<p>Before</p>
+<script>
+
+function it_keeps_going_and_going_and_going(i) {
+
+  return it_keeps_going_and_going_and_going(i+1);
+}
+
+it_keeps_going_and_going_and_going(1)
+</script>
+</script>
+<p>Afterwards</p>
+</body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index bb2918c..56482ec 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -6,6 +6,12 @@
 <body>
 <h1>JavaScript Tests</h1>
 
+<h2>Core</h2>
+<ul>
+<li><a href="core.recursion.html">Infinite Recursion</a></li>
+<li><a href="core.infinite.html">Infinite loop</a></li>
+</ul>
+
 
 <h2>Window</h2>
 <ul>
diff --git a/test/nsoption.c b/test/nsoption.c
new file mode 100644
index 0000000..1c9116a
--- /dev/null
+++ b/test/nsoption.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/nsoption.h"
+
+bool verbose_log = true;
+
+nserror gui_options_init_defaults(struct nsoption_s *defaults)
+{
+#if defined(riscos)
+	/* Set defaults for absent option strings */
+	nsoption_setnull_charp(ca_bundle, strdup("NetSurf:Resources.ca-bundle"));
+	nsoption_setnull_charp(cookie_file, strdup("NetSurf:Cookies"));
+	nsoption_setnull_charp(cookie_jar, strdup(CHOICES_PREFIX "Cookies"));
+
+	if (nsoption_charp(ca_bundle) == NULL ||
+	    nsoption_charp(cookie_file) == NULL ||
+	    nsoption_charp(cookie_jar) == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+#elif defined(nsgtk)
+	char *hdir = getenv("HOME");
+	char buf[PATH_MAX];
+
+	/* Set defaults for absent option strings */
+	snprintf(buf, PATH_MAX, "%s/.netsurf/Cookies", hdir);
+	nsoption_setnull_charp(cookie_file, strdup(buf));
+	nsoption_setnull_charp(cookie_jar, strdup(buf));
+	if (nsoption_charp(cookie_file) == NULL ||
+	    nsoption_charp(cookie_jar) == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	if (nsoption_charp(downloads_directory) == NULL) {
+		snprintf(buf, PATH_MAX, "%s/", hdir);
+		nsoption_set_charp(downloads_directory, strdup(buf));
+	}
+
+	if (nsoption_charp(url_file) == NULL) {
+		snprintf(buf, PATH_MAX, "%s/.netsurf/URLs", hdir);
+		nsoption_set_charp(url_file, strdup(buf));
+	}
+
+	if (nsoption_charp(hotlist_path) == NULL) {
+		snprintf(buf, PATH_MAX, "%s/.netsurf/Hotlist", hdir);
+		nsoption_set_charp(hotlist_path, strdup(buf));
+	}
+
+	nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs"));
+
+	if (nsoption_charp(url_file) == NULL ||
+	    nsoption_charp(ca_path) == NULL ||
+	    nsoption_charp(downloads_directory) == NULL ||
+	    nsoption_charp(hotlist_path) == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+#endif
+	return NSERROR_OK;
+}
+
+
+int main(int argc, char**argv)
+{
+	FILE *fp;
+
+	nsoption_init(gui_options_init_defaults, NULL, NULL);
+
+	nsoption_read("data/Choices", NULL);
+
+	nsoption_write("Choices-short", NULL, NULL);
+
+	fp = fopen("Choices-all", "w");
+
+	nsoption_dump(fp, NULL);
+
+	fclose(fp);
+
+	return 0;
+}
diff --git a/test/urldbtest.c b/test/urldbtest.c
index ab441ff..bc9d899 100644
--- a/test/urldbtest.c
+++ b/test/urldbtest.c
@@ -33,7 +33,7 @@
 #include "content/content.h"
 #include "content/urldb.h"
 #include "desktop/cookies.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #ifdef riscos
 /** \todo lose this */
 #include "riscos/bitmap.h"
diff --git a/utils/Makefile b/utils/Makefile
index ed34e95..aef5799 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -2,6 +2,6 @@
 
 S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c	\
 	libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c	\
-	utf8.c utils.c useragent.c
+	utf8.c utils.c useragent.c bloom.c nsoption.c
 
-S_UTILS := $(addprefix utils/,$(S_UTILS))
\ No newline at end of file
+S_UTILS := $(addprefix utils/,$(S_UTILS))
diff --git a/utils/bloom.c b/utils/bloom.c
new file mode 100644
index 0000000..1b07d6f
--- /dev/null
+++ b/utils/bloom.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2013 Rob Kendrick <rjek at netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Trivial bloom filter */
+
+#include <stdlib.h>
+#include "utils/bloom.h"
+
+/**
+ * Hash a string, returning a 32bit value.  The hash algorithm used is
+ * Fowler Noll Vo - a very fast and simple hash, ideal for short strings.
+ * See http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash for more details.
+ *
+ * \param  datum   The string to hash.
+ * \param  len	   size_t of data length.
+ * \return The calculated hash value for the datum.
+ */
+
+static inline uint32_t fnv(const char *datum, size_t len)
+{
+	uint32_t z = 0x811c9dc5;
+	
+	if (datum == NULL)
+		return 0;
+
+	while (len--) {
+		z *= 0x01000193;
+		z ^= *datum++;
+	}
+
+	return z;
+}
+
+struct bloom_filter {
+	size_t size;
+	uint32_t items;
+	uint8_t filter[];
+};
+
+struct bloom_filter *bloom_create(size_t size)
+{
+	struct bloom_filter *r = calloc(sizeof(*r) + size, 1);
+        
+	if (r == NULL)
+		return NULL;
+        
+	r->size = size;
+        
+	return r;
+}
+
+void bloom_destroy(struct bloom_filter *b)
+{
+        free(b);
+}
+
+void bloom_insert_str(struct bloom_filter *b, const char *s, size_t z)
+{
+	uint32_t hash = fnv(s, z);
+	bloom_insert_hash(b, hash);
+}
+
+void bloom_insert_hash(struct bloom_filter *b, uint32_t hash)
+{
+	unsigned int index = hash % (b->size << 3);
+	unsigned int byte_index = index >> 3;
+	unsigned int bit_index = index & 7;
+
+	b->filter[byte_index] |= (1 << bit_index);
+	b->items++;
+}
+
+bool bloom_search_str(struct bloom_filter *b, const char *s, size_t z)
+{
+	uint32_t hash = fnv(s, z);
+	return bloom_search_hash(b, hash);
+}
+
+bool bloom_search_hash(struct bloom_filter *b, uint32_t hash)
+{
+	unsigned int index = hash % (b->size << 3);
+	unsigned int byte_index = index >> 3;
+	unsigned int bit_index = index & 7;
+	
+	return (b->filter[byte_index] & (1 << bit_index)) != 0;
+}
+
+uint32_t bloom_items(struct bloom_filter *b)
+{
+	return b->items;
+}
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+int main(int argc, char *arg[])
+{
+	struct bloom_filter *b = bloom_create(8192);
+	FILE *dict = fopen("/usr/share/dict/words", "r");
+	char buf[BUFSIZ];
+	int false_positives = 0, total = 0;
+	
+	for (int i = 0; i < 8192; i++) {
+		fscanf(dict, "%s", buf);
+		printf("adding %s\n", buf);
+		bloom_insert_str(b, buf, strlen(buf));
+	}
+	
+	printf("adding NetSurf\n");
+	
+	bloom_insert_str(b, "NetSurf", 7);
+	printf("checking NetSurf (should be true)\n");
+	assert(bloom_search_str(b, "NetSurf", 7));
+	
+	fseek(dict, 0, SEEK_SET);
+	
+	for (int i = 0; i < 8192; i++) {
+		fscanf(dict, "%s", buf);
+		printf("checking %s (should be true)\n", buf);
+		assert(bloom_search_str(b, buf, strlen(buf)));
+		
+		total++;
+	}
+	
+	for (int i = 0; i < 8192; i++) {
+		fscanf(dict, "%s", buf);
+		printf("checking %s (should be false)\n", buf);
+		if (bloom_search_str(b, buf, strlen(buf)) == true)
+			false_positives++;
+		total++;
+	}
+	
+	printf("false positives: %d of %d, %f%%\n",
+		false_positives, total,
+		((float)false_positives / total) * 100);
+	
+	fclose(dict);
+	bloom_destroy(b);
+	
+	return 0;
+}
+
+#endif /* TEST_RIG */
+
diff --git a/utils/bloom.h b/utils/bloom.h
new file mode 100644
index 0000000..4a7bd38
--- /dev/null
+++ b/utils/bloom.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Rob Kendrick <rjek at netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Trivial bloom filter */
+
+#ifndef _NETSURF_UTILS_BLOOM_H_
+#define _NETSURF_UTILS_BLOOM_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct bloom_filter;
+
+/**
+ * Create a new bloom filter.
+ * 
+ * \param size Size of bloom filter in bytes
+ * \return Handle for newly-created bloom filter, or NULL
+ */
+struct bloom_filter *bloom_create(size_t size);
+
+/**
+ * Destroy a previously-created bloom filter
+ * 
+ * \param b Bloom filter to destroy
+ */
+void bloom_destroy(struct bloom_filter *b);
+
+/**
+ * Insert a string of given length (may include NULs) into the filter,
+ * using an internal hash function.
+ * 
+ * \param b Bloom filter to add to
+ * \param s Pointer to data
+ * \param z Length of data
+ */
+void bloom_insert_str(struct bloom_filter *b, const char *s, size_t z);
+
+/**
+ * Insert a given hash value into the filter, should you already have
+ * one to hand.
+ * 
+ * \param b Bloom filter to add to
+ * \param hash Value to add
+ */
+void bloom_insert_hash(struct bloom_filter *b, uint32_t hash);
+
+/**
+ * Search the filter for the given string, assuming it was added by
+ * bloom_insert_str().   May return false-positives.
+ * 
+ * \param b Bloom filter to search
+ * \param s Pointer to data to search for
+ * \param z Length of data
+ * 
+ * \return False if never added, True if it might have been.
+ */
+bool bloom_search_str(struct bloom_filter *b, const char *s, size_t z);
+
+/**
+ * Search the filter for the given hash value, assuming it was added by
+ * bloom_insert_hash().  May return false-positives.
+ * 
+ * \param b Bloom filter to search
+ * \param hash Hash value to search for
+ * 
+ * \return False if never added, True if it might have been.
+ */
+bool bloom_search_hash(struct bloom_filter *b, uint32_t hash);
+
+/**
+ * Find out how many items have been added to this bloom filter.  This
+ * is useful for deciding the size of a new bloom filter should you
+ * need to rehash it.
+ * 
+ * \param b Bloom filter to examine
+ * 
+ * \return Number of items that have been added
+ */
+uint32_t bloom_items(struct bloom_filter *b);
+
+#endif
diff --git a/utils/fetch-transifex.pl b/utils/fetch-transifex.pl
index d8d5882..4d40062 100644
--- a/utils/fetch-transifex.pl
+++ b/utils/fetch-transifex.pl
@@ -43,6 +43,9 @@ use constant GETOPT_SPEC =>
       password|w=s
       help|h|? );
 
+# ensure no locale translation is applied and leave it all in UTF-8
+use bytes;
+
 # default option values:
 my %opt = qw( resource messagesany project netsurf user netsurf );
 
diff --git a/utils/log.c b/utils/log.c
index 96a6d3c..2aa39ee 100644
--- a/utils/log.c
+++ b/utils/log.c
@@ -31,9 +31,9 @@ nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
 {
 	nserror ret = NSERROR_OK;
 
-	if (((*pargc) > 1) && 
-	    (argv[1][0] == '-') && 
-	    (argv[1][1] == 'v') && 
+	if (((*pargc) > 1) &&
+	    (argv[1][0] == '-') &&
+	    (argv[1][1] == 'v') &&
 	    (argv[1][2] == 0)) {
 		int argcmv;
 		for (argcmv = 2; argcmv < (*pargc); argcmv++) {
@@ -43,15 +43,17 @@ nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
 
 		/* ensure we actually show logging */
 		verbose_log = true;
-		
-		/* ensure stderr is available */
-		if (ensure != NULL) {
-			if (ensure(stderr) == false) {
-				/* failed to ensure output */
-				ret = NSERROR_INIT_FAILED;
-			}
-		}
 	}
+
+	/* ensure output file handle is correctly configured */
+	if ((verbose_log == true) &&
+	    (ensure != NULL) &&
+	    (ensure(stderr) == false)) {
+		/* failed to ensure output configuration */
+		ret = NSERROR_INIT_FAILED;
+		verbose_log = false;
+	}
+
 	return ret;
 }
 
diff --git a/utils/memdebug.c b/utils/memdebug.c
deleted file mode 100644
index 0f94f6f..0000000
--- a/utils/memdebug.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/** \file
- * Heap debugging functions (implementation).
- *
- * Based on memdebug.c from curl (see below), with the following modifications:
- *
- * - renamed functions from curl_ to memdebug_
- * - added memdebug_strndup
- * - added guard bytes before and after each block to help detect overflows
- * - if a guard byte is corrupted during free, dumps the DA to file
- */
-
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel at haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id: memdebug.c,v 1.1 2004/07/28 22:35:02 bursa Exp $
- ***************************************************************************/
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#ifdef riscos
-#include <unixlib/local.h>
-
-#include "oslib/os.h"
-#include "oslib/osfile.h"
-#endif
-
-#include "memdebug.h"
-
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-#define MAGIC 0x34343434
-#define GUARD 0x34
-
-#if defined(riscos) && !defined(__ELF__)
-extern int __dynamic_num;
-#endif
-
-struct memdebug {
-  size_t size;
-  unsigned int magic;
-  double mem[1];
-  /* I'm hoping this is the thing with the strictest alignment
-   * requirements.  That also means we waste some space :-( */
-};
-
-/*
- * Note that these debug functions are very simple and they are meant to
- * remain so. For advanced analysis, record a log file and write perl scripts
- * to analyze them!
- *
- * Don't use these with multithreaded test programs!
- */
-
-#define logfile memdebug_debuglogfile
-FILE *memdebug_debuglogfile;
-static bool memlimit; /* enable memory limit */
-static long memsize;  /* set number of mallocs allowed */
-
-/* this sets the log file name */
-void memdebug_memdebug(const char *logname)
-{
-  if(logname)
-    logfile = fopen(logname, "w");
-  else
-    logfile = stderr;
-}
-
-/* This function sets the number of malloc() calls that should return
-   successfully! */
-void memdebug_memlimit(long limit)
-{
-  memlimit = true;
-  memsize = limit;
-}
-
-/* returns true if this isn't allowed! */
-static bool countcheck(const char *func, int line, const char *source)
-{
-  /* if source is NULL, then the call is made internally and this check
-     should not be made */
-  if(memlimit && source) {
-    if(!memsize) {
-      if(logfile && source)
-        fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
-                source, line, func);
-      if(source)
-        fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
-                source, line, func);
-      return true; /* RETURN ERROR! */
-    }
-    else
-      memsize--; /* countdown */
-
-    /* log the countdown */
-    if(logfile && source)
-      fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
-              source, line, memsize);
-
-  }
-
-  return false; /* allow this */
-}
-
-void *memdebug_malloc(size_t wantedsize, int line, const char *source)
-{
-  struct memdebug *mem;
-  size_t size;
-
-  if(countcheck("malloc", line, source))
-    return NULL;
-
-  /* alloc at least 64 bytes */
-  size = sizeof(struct memdebug)+wantedsize + 8;
-
-  mem=(struct memdebug *)(malloc)(size);
-  if(mem) {
-    unsigned int i;
-    /* fill memory with junk */
-    memset(mem->mem, 0xA5, wantedsize);
-    mem->size = wantedsize;
-    mem->magic = MAGIC;
-    for (i = 0; i != 8; i++)
-      ((char *) mem->mem)[wantedsize + i] = GUARD;
-  }
-
-  if(logfile && source)
-    fprintf(logfile, "MEM %s:%d malloc(%zu) = %p\n",
-            source, line, wantedsize, mem ? mem->mem : 0);
-  return (mem ? mem->mem : NULL);
-}
-
-void *memdebug_calloc(size_t wanted_elements, size_t wanted_size,
-                    int line, const char *source)
-{
-  struct memdebug *mem;
-  size_t size, user_size;
-
-  if(countcheck("calloc", line, source))
-    return NULL;
-
-  /* alloc at least 64 bytes */
-  user_size = wanted_size * wanted_elements;
-  size = sizeof(struct memdebug) + user_size + 8;
-
-  mem = (struct memdebug *)(malloc)(size);
-  if(mem) {
-    unsigned int i;
-    /* fill memory with zeroes */
-    memset(mem->mem, 0, user_size);
-    mem->size = user_size;
-    mem->magic = MAGIC;
-    for (i = 0; i != 8; i++)
-      ((char *) mem->mem)[mem->size + i] = GUARD;
-  }
-
-  if(logfile && source)
-    fprintf(logfile, "MEM %s:%d calloc(%zu,%zu) = %p\n",
-            source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
-  return (mem ? mem->mem : NULL);
-}
-
-char *memdebug_strdup(const char *str, int line, const char *source)
-{
-  char *mem;
-  size_t len;
-
-  assert(str != NULL);
-
-  if(countcheck("strdup", line, source))
-    return NULL;
-
-  len=strlen(str)+1;
-
-  mem=memdebug_malloc(len, 0, NULL); /* NULL prevents logging */
-  if (mem)
-  memcpy(mem, str, len);
-
-  if(logfile)
-    fprintf(logfile, "MEM %s:%d strdup(%p) (%zu) = %p\n",
-            source, line, str, len, mem);
-
-  return mem;
-}
-
-char *memdebug_strndup(const char *str, size_t size, int line, const char *source)
-{
-  char *mem;
-  size_t len;
-
-  assert(str != NULL);
-
-  if(countcheck("strndup", line, source))
-    return NULL;
-
-  len=strlen(str)+1;
-  if (size < len - 1)
-    len = size + 1;
-
-  mem=memdebug_malloc(len, 0, NULL); /* NULL prevents logging */
-  if (mem) {
-  memcpy(mem, str, len);
-  mem[len - 1] = 0;
-  }
-
-  if(logfile)
-    fprintf(logfile, "MEM %s:%d strndup(%p, %zd) (%zu) = %p\n",
-            source, line, str, size, len, mem);
-
-  return mem;
-}
-
-/* We provide a realloc() that accepts a NULL as pointer, which then
-   performs a malloc(). In order to work with ares. */
-void *memdebug_realloc(void *ptr, size_t wantedsize,
-                     int line, const char *source)
-{
-  unsigned int i;
-  struct memdebug *mem=NULL;
-
-  size_t size = sizeof(struct memdebug)+wantedsize+8;
-
-  if(countcheck("realloc", line, source))
-    return NULL;
-
-  if(ptr) {
-    mem = (struct memdebug *)(void *)
-		((char *)ptr - offsetof(struct memdebug, mem));
-  }
-
-  if(logfile) {
-    if (mem && mem->magic != MAGIC)
-      fprintf(logfile, "MAGIC match failed!\n");
-    for (i = 0; mem && i != 8; i++)
-      if (((char *) mem->mem)[mem->size + i] != GUARD)
-        fprintf(logfile, "GUARD %u match failed!\n", i);
-    fprintf(logfile, "MEM %s:%d realloc(%p, %zu) = ",
-            source, line, ptr, wantedsize);
-    fflush(logfile);
-  }
-
-  mem=(struct memdebug *)(realloc)(mem, size);
-  if(logfile)
-    fprintf(logfile, "%p\n", mem?mem->mem:NULL);
-
-  if(mem) {
-    mem->size = wantedsize;
-    mem->magic = MAGIC;
-    for (i = 0; i != 8; i++)
-      ((char *) mem->mem)[wantedsize + i] = GUARD;
-    return mem->mem;
-  }
-
-  return NULL;
-}
-
-void memdebug_free(void *ptr, int line, const char *source)
-{
-  unsigned int i;
-  struct memdebug *mem;
-
-  if (!ptr)
-    return;
-
-  assert(ptr != NULL);
-
-  mem = (struct memdebug *)(void *)
-		((char *)ptr - offsetof(struct memdebug, mem));
-  if(logfile) {
-    fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
-    if (mem->magic != MAGIC) {
-      fprintf(logfile, "MAGIC match failed!\n");
-#ifdef riscos
-  #ifndef __ELF__
-      if (__dynamic_num != -1) {
-        int size;
-        byte *base_address;
-        xosdynamicarea_read(__dynamic_num, &size, &base_address,
-            0, 0, 0, 0, 0);
-        fprintf(logfile, "saving DA %i %p %x\n", __dynamic_num, base_address,
-            size);
-        xosfile_save("core", (bits) base_address, 0, base_address,
-            base_address + size);
-      }
-  #else
-      __unixlib_write_coredump(NULL);
-  #endif
-#endif
-    }
-    fflush(logfile);
-    for (i = 0; i != 8; i++)
-      if (((char *) mem->mem)[mem->size + i] != GUARD)
-        fprintf(logfile, "GUARD %u match failed!\n", i);
-    fflush(logfile);
-  }
-
-  /* destroy  */
-  memset(mem->mem, 0x13, mem->size);
-  mem->magic = 0x13131313;
-  for (i = 0; i != 8; i++)
-    ((char *) mem->mem)[mem->size + i] = 0x13;
-
-  /* free for real */
-  (free)(mem);
-}
-
-int memdebug_socket(int domain, int type, int protocol, int line,
-                const char *source)
-{
-  int sockfd=(socket)(domain, type, protocol);
-  if(logfile && (sockfd!=-1))
-    fprintf(logfile, "FD %s:%d socket() = %d\n",
-            source, line, sockfd);
-  return sockfd;
-}
-
-int memdebug_accept(int s, void *saddr, void *saddrlen,
-                int line, const char *source)
-{
-  struct sockaddr *addr = (struct sockaddr *)saddr;
-  socklen_t *addrlen = (socklen_t *)saddrlen;
-  int sockfd=(accept)(s, addr, addrlen);
-  if(logfile)
-    fprintf(logfile, "FD %s:%d accept() = %d\n",
-            source, line, sockfd);
-  return sockfd;
-}
-
-/* this is our own defined way to close sockets on *ALL* platforms */
-int memdebug_sclose(int sockfd, int line, const char *source)
-{
-  int res=sclose(sockfd);
-  if(logfile)
-    fprintf(logfile, "FD %s:%d sclose(%d)\n",
-            source, line, sockfd);
-  return res;
-}
-
-FILE *memdebug_fopen(const char *file, const char *mode,
-                 int line, const char *source)
-{
-  FILE *res=(fopen)(file, mode);
-  if(logfile)
-    fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
-            source, line, file, mode, res);
-  return res;
-}
-
-int memdebug_fclose(FILE *file, int line, const char *source)
-{
-  int res;
-
-  assert(file != NULL);
-
-  res=(fclose)(file);
-  if(logfile)
-    fprintf(logfile, "FILE %s:%d fclose(%p)\n",
-            source, line, file);
-  return res;
-}
diff --git a/utils/memdebug.h b/utils/memdebug.h
deleted file mode 100644
index bdf933c..0000000
--- a/utils/memdebug.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/** \file
- * Heap debugging functions (interface).
- *
- * Based on memdebug.h from curl (see below), with the following modifications:
- *
- * - renamed functions from curl_ to memdebug_
- * - added memdebug_strndup
- * - added guard bytes before and after each block to help detect overflows
- * - if a guard byte is corrupted during free, dumps the DA to file
- */
-
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel at haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id: memdebug.h,v 1.1 2004/07/28 22:35:02 bursa Exp $
- ***************************************************************************/
-
-#ifndef _MEMDEBUG_H_
-#define _MEMDEBUG_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#define logfile memdebug_debuglogfile
-
-extern FILE *logfile;
-
-/* memory functions */
-void *memdebug_malloc(size_t size, int line, const char *source);
-void *memdebug_calloc(size_t elements, size_t size, int line, const char *source);
-void *memdebug_realloc(void *ptr, size_t size, int line, const char *source);
-void memdebug_free(void *ptr, int line, const char *source);
-char *memdebug_strdup(const char *str, int line, const char *source);
-char *memdebug_strndup(const char *str, size_t size, int line, const char *source);
-void memdebug_memdebug(const char *logname);
-void memdebug_memlimit(long limit);
-
-/* file descriptor manipulators */
-int memdebug_socket(int domain, int type, int protocol, int line , const char *);
-int memdebug_sclose(int sockfd, int, const char *source);
-int memdebug_accept(int s, void *addr, void *addrlen,
-                int line, const char *source);
-
-/* FILE functions */
-FILE *memdebug_fopen(const char *file, const char *mode, int line,
-                 const char *source);
-int memdebug_fclose(FILE *file, int line, const char *source);
-
-#ifndef MEMDEBUG_NODEFINES
-
-#undef strdup
-#define strdup(ptr) memdebug_strdup(ptr, __LINE__, __FILE__)
-#define strndup(ptr,size) memdebug_strndup(ptr, size, __LINE__, __FILE__)
-#define malloc(size) memdebug_malloc(size, __LINE__, __FILE__)
-#define calloc(nbelem,size) memdebug_calloc(nbelem, size, __LINE__, __FILE__)
-#define realloc(ptr,size) memdebug_realloc(ptr, size, __LINE__, __FILE__)
-#define free(ptr) memdebug_free(ptr, __LINE__, __FILE__)
-
-#define socket(domain,type,protocol)\
- memdebug_socket(domain,type,protocol,__LINE__,__FILE__)
-#undef accept /* for those with accept as a macro */
-#define accept(sock,addr,len)\
- memdebug_accept(sock,addr,len,__LINE__,__FILE__)
-
-#define getaddrinfo(host,serv,hint,res) \
-  memdebug_getaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
-#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
-  memdebug_getnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
-  __FILE__)
-#define freeaddrinfo(data) \
-  memdebug_freeaddrinfo(data,__LINE__,__FILE__)
-
-/* sclose is probably already defined, redefine it! */
-#undef sclose
-#define sclose(sockfd) memdebug_sclose(sockfd,__LINE__,__FILE__)
-/* ares-adjusted define: */
-#undef closesocket
-#define closesocket(sockfd) memdebug_sclose(sockfd,__LINE__,__FILE__)
-
-#undef fopen
-#define fopen(file,mode) memdebug_fopen(file,mode,__LINE__,__FILE__)
-#define fclose(file) memdebug_fclose(file,__LINE__,__FILE__)
-
-#endif /* MEMDEBUG_NODEFINES */
-
-#endif
diff --git a/utils/nsoption.c b/utils/nsoption.c
new file mode 100644
index 0000000..f6244cd
--- /dev/null
+++ b/utils/nsoption.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Option reading and saving (implementation).
+ *
+ * Options are stored in the format key:value, one per line.
+ *
+ * For bool options, value is "0" or "1".
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "desktop/plot_style.h"
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/nsoption.h"
+
+struct nsoption_s *nsoptions = NULL;
+struct nsoption_s *nsoptions_default = NULL;
+
+#define NSOPTION_BOOL(NAME, DEFAULT) \
+	{ #NAME, sizeof(#NAME) - 1, OPTION_BOOL, { .b = DEFAULT } },
+
+#define NSOPTION_STRING(NAME, DEFAULT) \
+	{ #NAME, sizeof(#NAME) - 1, OPTION_STRING, { .cs = DEFAULT } },
+
+#define NSOPTION_INTEGER(NAME, DEFAULT) \
+	{ #NAME, sizeof(#NAME) - 1, OPTION_INTEGER, { .i = DEFAULT } },
+
+#define NSOPTION_UINT(NAME, DEFAULT) \
+	{ #NAME, sizeof(#NAME) - 1, OPTION_UINT, { .u = DEFAULT } },
+
+#define NSOPTION_COLOUR(NAME, DEFAULT) \
+	{ #NAME, sizeof(#NAME) - 1, OPTION_COLOUR, { .c = DEFAULT } },
+
+/** The table of compiled in default options */
+static struct nsoption_s defaults[] = {
+#include "desktop/options.h"
+
+#if defined(riscos)
+#include "riscos/options.h"
+#elif defined(nsgtk)
+#include "gtk/options.h"
+#elif defined(nsbeos)
+#include "beos/options.h"
+#elif defined(nsamiga)
+#include "amiga/options.h"
+#elif defined(nsframebuffer)
+#include "framebuffer/options.h"
+#elif defined(nsatari)
+#include "atari/options.h"
+#elif defined(nsmonkey)
+#include "monkey/options.h"
+#endif
+	{ NULL, 0, OPTION_INTEGER, { 0 } }
+};
+
+#undef NSOPTION_BOOL
+#undef NSOPTION_STRING
+#undef NSOPTION_INTEGER
+#undef NSOPTION_UINT
+#undef NSOPTION_COLOUR
+
+/**
+ * Set an option value based on a string
+ */
+static bool
+strtooption(const char *value, struct nsoption_s *option)
+{
+	bool ret = true;
+	colour rgbcolour; /* RRGGBB */
+
+	switch (option->type) {
+	case OPTION_BOOL:
+		option->value.b = (value[0] == '1');
+		break;
+
+	case OPTION_INTEGER:
+		option->value.i = atoi(value);
+		break;
+
+	case OPTION_UINT:
+		option->value.u = strtoul(value, NULL, 0);
+		break;
+
+	case OPTION_COLOUR:
+		if (sscanf(value, "%x", &rgbcolour) == 1) {
+			option->value.c = (((0x000000FF & rgbcolour) << 16) |
+					   ((0x0000FF00 & rgbcolour) << 0) |
+					   ((0x00FF0000 & rgbcolour) >> 16));
+		}
+		break;
+
+	case OPTION_STRING:
+		if (option->value.s != NULL) {
+			free(option->value.s);
+		}
+
+		if (*value == 0) {
+			/* do not allow empty strings in text options */
+			option->value.s = NULL;
+		} else {
+			option->value.s = strdup(value);
+		}
+		break;
+
+	default:
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+/* validate options to sane values */
+static void nsoption_validate(struct nsoption_s *opts, struct nsoption_s *defs)
+{
+	int cloop;
+	bool black = true;
+
+	if (opts[NSOPTION_font_size].value.i  < 50) {
+		opts[NSOPTION_font_size].value.i = 50;
+	}
+
+	if (opts[NSOPTION_font_size].value.i > 1000) {
+		opts[NSOPTION_font_size].value.i = 1000;
+	}
+
+	if (opts[NSOPTION_font_min_size].value.i < 10) {
+		opts[NSOPTION_font_min_size].value.i = 10;
+	}
+
+	if (opts[NSOPTION_font_min_size].value.i > 500) {
+		opts[NSOPTION_font_min_size].value.i = 500;
+	}
+
+	if (opts[NSOPTION_memory_cache_size].value.i < 0) {
+		opts[NSOPTION_memory_cache_size].value.i = 0;
+	}
+
+	/* to aid migration from old, broken, configuration files this
+	 * checks to see if all the system colours are set to black
+	 * and returns them to defaults instead
+	 */
+
+	for (cloop = NSOPTION_SYS_COLOUR_START;
+	     cloop <= NSOPTION_SYS_COLOUR_END;
+	     cloop++) {
+		if (opts[cloop].value.c != 0) {
+			black = false;
+			break;
+		}
+	}
+	if (black == true) {
+		for (cloop = NSOPTION_SYS_COLOUR_START;
+		     cloop <= NSOPTION_SYS_COLOUR_END;
+		     cloop++) {
+			opts[cloop].value.c = defs[cloop].value.c;
+		}
+	}
+}
+
+/**
+ * Determines if an option is different between two option tables.
+ *
+ * @param opts The first table to compare.
+ * @param defs The second table to compare.
+ * @param entry The option to compare.
+ * @return true if the option differs false if not.
+ */
+static bool
+nsoption_is_set(const struct nsoption_s *opts,
+		const struct nsoption_s *defs,
+		const enum nsoption_e entry)
+{
+	bool ret = false;
+
+	switch (opts[entry].type) {
+	case OPTION_BOOL:
+		if (opts[entry].value.b != defs[entry].value.b) {
+			ret = true;
+		}
+		break;
+
+	case OPTION_INTEGER:
+		if (opts[entry].value.i != defs[entry].value.i) {
+			ret = true;
+		}
+		break;
+
+	case OPTION_UINT:
+		if (opts[entry].value.u != defs[entry].value.u) {
+			ret = true;
+		}
+		break;
+
+	case OPTION_COLOUR:
+		if (opts[entry].value.c != defs[entry].value.c) {
+			ret = true;
+		}
+		break;
+
+	case OPTION_STRING:
+		/* set if:
+		 *  - defs is null.
+		 *  - default is null but value is not.
+		 *  - default and value pointers are different
+		 *    (acts as a null check because of previous check)
+		 *    and the strings content differ.
+		 */
+		if (((defs[entry].value.s == NULL) &&
+		     (opts[entry].value.s != NULL)) ||
+		    ((defs[entry].value.s != opts[entry].value.s) &&
+		     (strcmp(opts[entry].value.s, defs[entry].value.s) != 0))) {
+			ret = true;
+		}
+		break;
+
+	}
+	return ret;
+}
+
+/**
+ * Output choices to file stream
+ *
+ * @param fp The file stream to write to.
+ * @param opts The options table to write.
+ * @param defs The default value table to compare with.
+ * @param all Output all entries not just ones changed from defaults
+ */
+static nserror
+nsoption_output(FILE *fp,
+		struct nsoption_s *opts,
+		struct nsoption_s *defs,
+		bool all)
+{
+	unsigned int entry; /* index to option being output */
+	colour rgbcolour; /* RRGGBB */
+
+	for (entry = 0; entry < NSOPTION_LISTEND; entry++) {
+		if ((all == false) &&
+		    (nsoption_is_set(opts, defs, entry) == false)) {
+			continue;
+		}
+
+		switch (opts[entry].type) {
+		case OPTION_BOOL:
+			fprintf(fp, "%s:%c\n",
+				opts[entry].key,
+				opts[entry].value.b ? '1' : '0');
+			break;
+
+		case OPTION_INTEGER:
+			fprintf(fp, "%s:%i\n",
+				opts[entry].key,
+				opts[entry].value.i);
+
+			break;
+
+		case OPTION_UINT:
+			fprintf(fp, "%s:%u\n",
+				opts[entry].key,
+				opts[entry].value.u);
+			break;
+
+		case OPTION_COLOUR:
+			rgbcolour = (((0x000000FF & opts[entry].value.c) << 16) |
+				     ((0x0000FF00 & opts[entry].value.c) << 0) |
+				     ((0x00FF0000 & opts[entry].value.c) >> 16));
+			fprintf(fp, "%s:%06x\n",
+				opts[entry].key,
+				rgbcolour);
+
+			break;
+
+		case OPTION_STRING:
+			fprintf(fp, "%s:%s\n",
+				opts[entry].key,
+				((opts[entry].value.s == NULL) ||
+				 (*opts[entry].value.s == 0)) ? "" : opts[entry].value.s);
+
+			break;
+		}
+	}
+
+	return NSERROR_OK;
+}
+
+/**
+ * Output an option value into a string, in HTML format.
+ *
+ * @param option The option to output the value of.
+ * @param size The size of the string buffer.
+ * @param pos The current position in string
+ * @param string The string in which to output the value.
+ * @return The number of bytes written to string or -1 on error
+ */
+static size_t
+nsoption_output_value_html(struct nsoption_s *option,
+			   size_t size,
+			   size_t pos,
+			   char *string)
+{
+	size_t slen = 0; /* length added to string */
+	colour rgbcolour; /* RRGGBB */
+
+	switch (option->type) {
+	case OPTION_BOOL:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%s",
+				option->value.b ? "true" : "false");
+		break;
+
+	case OPTION_INTEGER:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%i",
+				option->value.i);
+		break;
+
+	case OPTION_UINT:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%u",
+				option->value.u);
+		break;
+
+	case OPTION_COLOUR:
+		rgbcolour = (((0x000000FF & option->value.c) << 16) |
+			     ((0x0000FF00 & option->value.c) << 0) |
+			     ((0x00FF0000 & option->value.c) >> 16));
+		slen = snprintf(string + pos,
+				size - pos,
+				"<span style=\"background-color: #%06x; "
+				"color: #%06x; "
+				"font-family:Monospace; \">#%06X</span>",
+				rgbcolour,
+				colour_to_bw_furthest(rgbcolour),
+				rgbcolour);
+		break;
+
+	case OPTION_STRING:
+		if (option->value.s != NULL) {
+			slen = snprintf(string + pos, size - pos, "%s",
+					option->value.s);
+		} else {
+			slen = snprintf(string + pos, size - pos,
+					"<span class=\"null-content\">NULL"
+					"</span>");
+		}
+		break;
+	}
+
+	return slen;
+}
+
+
+/**
+ * Output an option value into a string, in plain text format.
+ *
+ * @param option The option to output the value of.
+ * @param size The size of the string buffer.
+ * @param pos The current position in string
+ * @param string The string in which to output the value.
+ * @return The number of bytes written to string or -1 on error
+ */
+static size_t
+nsoption_output_value_text(struct nsoption_s *option,
+			   size_t size,
+			   size_t pos,
+			   char *string)
+{
+	size_t slen = 0; /* length added to string */
+	colour rgbcolour; /* RRGGBB */
+
+	switch (option->type) {
+	case OPTION_BOOL:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%c",
+				option->value.b ? '1' : '0');
+		break;
+
+	case OPTION_INTEGER:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%i",
+				option->value.i);
+		break;
+
+	case OPTION_UINT:
+		slen = snprintf(string + pos,
+				size - pos,
+				"%u",
+				option->value.u);
+		break;
+
+	case OPTION_COLOUR:
+		rgbcolour = (((0x000000FF & option->value.c) << 16) |
+			     ((0x0000FF00 & option->value.c) << 0) |
+			     ((0x00FF0000 & option->value.c) >> 16));
+		slen = snprintf(string + pos, size - pos, "%06x", rgbcolour);
+		break;
+
+	case OPTION_STRING:
+		if (option->value.s != NULL) {
+			slen = snprintf(string + pos,
+					size - pos,
+					"%s",
+					option->value.s);
+		}
+		break;
+	}
+
+	return slen;
+}
+
+/**
+ * Duplicates an option table.
+ *
+ * Allocates a new option table and copies an existing one into it.
+ *
+ * @param src The source table to copy
+ */
+static nserror
+nsoption_dup(struct nsoption_s *src, struct nsoption_s **pdst)
+{
+	struct nsoption_s *dst;
+	dst = malloc(sizeof(defaults));
+	if (dst == NULL) {
+		return NSERROR_NOMEM;
+	}
+	*pdst = dst;
+
+	/* copy the source table into the destination table */
+	memcpy(dst, src, sizeof(defaults));
+
+	while (src->key != NULL) {
+		if ((src->type == OPTION_STRING) &&
+		    (src->value.s != NULL)) {
+			dst->value.s = strdup(src->value.s);
+		}
+		src++;
+		dst++;
+	}
+
+	return NSERROR_OK;
+}
+
+/**
+ * frees an option table.
+ *
+ * Iterates through an option table a freeing resources as required
+ * finally freeing the option table itself.
+ *
+ * @param opts The option table to free.
+ */
+static nserror
+nsoption_free(struct nsoption_s *opts)
+{
+	struct nsoption_s *cur; /* option being freed */
+
+	if (opts == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	cur = opts;
+
+	while (cur->key != NULL) {
+		if ((cur->type == OPTION_STRING) && (cur->value.s != NULL)) {
+			free(cur->value.s);
+		}
+		cur++;
+	}
+	free(opts);
+
+	return NSERROR_OK;
+}
+
+
+/* exported interface documented in utils/nsoption.h */
+nserror
+nsoption_init(nsoption_set_default_t *set_defaults,
+	      struct nsoption_s **popts,
+	      struct nsoption_s **pdefs)
+{
+	nserror ret;
+	struct nsoption_s *defs;
+	struct nsoption_s *opts;
+
+	ret = nsoption_dup(&defaults[0], &defs);
+	if (ret != NSERROR_OK) {
+		return ret;
+	}
+
+	/* update the default table */
+	if (set_defaults != NULL) {
+		/** @todo it would be better if the frontends actually
+		 * set values in the passed in table instead of
+		 * assuming the global one.
+		 */
+		opts = nsoptions;
+		nsoptions = defs;
+
+		ret = set_defaults(defs);
+
+		if (ret != NSERROR_OK) {
+			nsoptions = opts;
+			nsoption_free(defs);
+			return ret;
+		}
+	}
+
+	/* copy the default values into the working set */
+	ret = nsoption_dup(defs, &opts);
+	if (ret != NSERROR_OK) {
+		nsoption_free(defs);
+		return ret;
+	}
+
+	/* return values if wanted */
+	if (popts != NULL) {
+		*popts = opts;
+	} else {
+		nsoptions = opts;
+	}
+
+	if (pdefs != NULL) {
+		*pdefs = defs;
+	} else {
+		nsoptions_default = defs;
+	}
+
+	return NSERROR_OK;
+}
+
+/* exported interface documented in utils/nsoption.h */
+nserror nsoption_finalise(struct nsoption_s *opts, struct nsoption_s *defs)
+{
+	/* check to see if global table selected */
+	if (opts == NULL) {
+		opts = nsoptions;
+	}
+
+	nsoption_free(opts);
+
+	/* check to see if global table selected */
+	if (defs == NULL) {
+		defs = nsoptions_default;
+	}
+
+	nsoption_free(defs);
+
+	return NSERROR_OK;
+}
+
+/* exported interface documented in utils/nsoption.h */
+nserror
+nsoption_read(const char *path, struct nsoption_s *opts)
+{
+	char s[100];
+	FILE *fp;
+	struct nsoption_s *defs;
+
+	if (path == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	/* check to see if global table selected */
+	if (opts == NULL) {
+		opts = nsoptions;
+	}
+
+	/** @todo is this and API bug not being a parameter */
+	defs = nsoptions_default;
+
+	fp = fopen(path, "r");
+	if (!fp) {
+		LOG(("Failed to open file '%s'", path));
+		return NSERROR_NOT_FOUND;
+	}
+
+	LOG(("Sucessfully opened '%s' for Options file", path));
+
+	while (fgets(s, 100, fp)) {
+		char *colon, *value;
+		unsigned int idx;
+
+		if ((s[0] == 0) || (s[0] == '#')) {
+			continue;
+		}
+
+		colon = strchr(s, ':');
+		if (colon == 0) {
+			continue;
+		}
+
+		s[strlen(s) - 1] = 0;  /* remove \n at end */
+		*colon = 0;  /* terminate key */
+		value = colon + 1;
+
+		for (idx = 0; opts[idx].key != NULL; idx++) {
+			if (strcasecmp(s, opts[idx].key) != 0) {
+				continue;
+			}
+
+			strtooption(value, &opts[idx]);
+			break;
+		}
+	}
+
+	fclose(fp);
+
+	nsoption_validate(opts, defs);
+
+	return NSERROR_OK;
+}
+
+
+/* exported interface documented in utils/nsoption.h */
+nserror
+nsoption_write(const char *path,
+	       struct nsoption_s *opts,
+	       struct nsoption_s *defs)
+{
+	FILE *fp;
+	nserror ret;
+
+	if (path == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	/* check to see if global table selected */
+	if (opts == NULL) {
+		opts = nsoptions;
+	}
+
+	/* check to see if global table selected */
+	if (defs == NULL) {
+		defs = nsoptions_default;
+	}
+
+	fp = fopen(path, "w");
+	if (!fp) {
+		LOG(("failed to open file '%s' for writing", path));
+		return NSERROR_NOT_FOUND;
+	}
+
+	ret = nsoption_output(fp, opts, defs, false);
+
+	fclose(fp);
+
+	return ret;
+}
+
+/* exported interface documented in utils/nsoption.h */
+nserror
+nsoption_dump(FILE *outf, struct nsoption_s *opts)
+{
+	if (outf == NULL) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	/* check to see if global table selected */
+	if (opts == NULL) {
+		opts = nsoptions;
+	}
+
+	return nsoption_output(outf, opts, NULL, true);
+}
+
+
+/* exported interface documented in utils/nsoption.h */
+nserror
+nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
+{
+	char *arg;
+	char *val;
+	int arglen;
+	int idx = 1;
+	int mv_loop;
+	unsigned int entry_loop;
+
+	/* check to see if global table selected */
+	if (opts == NULL) {
+		opts = nsoptions;
+	}
+
+	while (idx < *pargc) {
+		arg = argv[idx];
+		arglen = strlen(arg);
+
+		/* check we have an option */
+		/* option must start -- and be as long as the shortest option*/
+		if ((arglen < (2+5) ) || (arg[0] != '-') || (arg[1] != '-'))
+			break;
+
+		arg += 2; /* skip -- */
+
+		val = strchr(arg, '=');
+		if (val == NULL) {
+			/* no equals sign - next parameter is val */
+			idx++;
+			if (idx >= *pargc)
+				break;
+			val = argv[idx];
+		} else {
+			/* equals sign */
+			arglen = val - arg ;
+			val++;
+		}
+
+		/* arg+arglen is the option to set, val is the value */
+
+		LOG(("%.*s = %s", arglen, arg, val));
+
+		for (entry_loop = 0;
+		     entry_loop < NSOPTION_LISTEND;
+		     entry_loop++) {
+			if (strncmp(arg, opts[entry_loop].key, arglen) == 0) {
+				strtooption(val, opts + entry_loop);
+				break;
+			}
+		}
+
+		idx++;
+	}
+
+	/* remove processed options from argv */
+	for (mv_loop=0; mv_loop < (*pargc - idx); mv_loop++) {
+		argv[mv_loop + 1] = argv[mv_loop + idx];
+	}
+	*pargc -= (idx - 1);
+
+	return NSERROR_OK;
+}
+
+/* exported interface documented in options.h */
+int
+nsoption_snoptionf(char *string,
+		   size_t size,
+		   enum nsoption_e option_idx,
+		   const char *fmt)
+{
+	size_t slen = 0; /* current output string length */
+	int fmtc = 0; /* current index into format string */
+	struct nsoption_s *option;
+
+	if (option_idx >= NSOPTION_LISTEND) {
+		return -1;
+	}
+
+	option = &nsoptions[option_idx]; /* assume the global table */
+	if (option == NULL || option->key == NULL)
+		return -1;
+
+
+	while ((slen < size) && (fmt[fmtc] != 0)) {
+		if (fmt[fmtc] == '%') {
+			fmtc++;
+			switch (fmt[fmtc]) {
+			case 'k':
+				slen += snprintf(string + slen,
+						 size - slen,
+						 "%s",
+						 option->key);
+				break;
+
+			case 'p':
+				if (nsoption_is_set(nsoptions,
+						    nsoptions_default,
+						    option_idx)) {
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "user");
+				} else {
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "default");
+				}
+				break;
+
+			case 't':
+				switch (option->type) {
+				case OPTION_BOOL:
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "boolean");
+					break;
+
+				case OPTION_INTEGER:
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "integer");
+					break;
+
+				case OPTION_UINT:
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "unsigned integer");
+					break;
+
+				case OPTION_COLOUR:
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "colour");
+					break;
+
+				case OPTION_STRING:
+					slen += snprintf(string + slen,
+							 size - slen,
+							 "string");
+					break;
+
+				}
+				break;
+
+
+			case 'V':
+				slen += nsoption_output_value_html(option,
+								   size,
+								   slen,
+								   string);
+				break;
+			case 'v':
+				slen += nsoption_output_value_text(option,
+								   size,
+								   slen,
+								   string);
+				break;
+			}
+			fmtc++;
+		} else {
+			string[slen] = fmt[fmtc];
+			slen++;
+			fmtc++;
+		}
+	}
+
+	/* Ensure that we NUL-terminate the output */
+	string[min(slen, size - 1)] = '\0';
+
+	return slen;
+}
+
+/* exported interface documented in options.h */
+nserror
+nsoption_set_tbl_charp(struct nsoption_s *opts,
+		       enum nsoption_e option_idx,
+		       char *s)
+{
+	struct nsoption_s *option;
+
+	option = &opts[option_idx];
+
+	/* ensure it is a string option */
+	if (option->type != OPTION_STRING) {
+		return NSERROR_BAD_PARAMETER;
+	}
+
+	/* free any existing string */
+	if (option->value.s != NULL) {
+		free(option->value.s);
+	}
+
+	option->value.s = s;
+
+	/* check for empty string */
+	if ((option->value.s != NULL) && (*option->value.s == 0)) {
+		free(option->value.s);
+		option->value.s = NULL;
+	}
+	return NSERROR_OK;
+}
diff --git a/utils/nsoption.h b/utils/nsoption.h
new file mode 100644
index 0000000..d111729
--- /dev/null
+++ b/utils/nsoption.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince at netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Option reading and saving (interface).
+ *
+ * Global options are defined in desktop/options.h
+ * Distinct target options are defined in <TARGET>/options.h
+ *
+ * The implementation API is slightly compromised because it still has
+ * "global" tables for both the default and current option tables.
+ *
+ * The initialisation and read/write interfaces take pointers to an
+ * option table which would let us to make the option structure
+ * opaque.
+ *
+ * All the actual acessors assume direct access to a global option
+ * table (nsoptions). To avoid this the acessors would have to take a
+ * pointer to the active options table and be implemented as functions
+ * within nsoptions.c
+ *
+ * Indirect access would have an impact on performance of NetSurf as
+ * the expected option lookup cost is currently that of a simple
+ * dereference (which this current implementation keeps).
+ */
+
+#ifndef _NETSURF_UTILS_NSOPTION_H_
+#define _NETSURF_UTILS_NSOPTION_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "utils/errors.h"
+
+/* allow targets to include any necessary headers of their own */
+#define NSOPTION_BOOL(NAME, DEFAULT)
+#define NSOPTION_STRING(NAME, DEFAULT)
+#define NSOPTION_INTEGER(NAME, DEFAULT)
+#define NSOPTION_UINT(NAME, DEFAULT)
+#define NSOPTION_COLOUR(NAME, DEFAULT)
+
+#include "desktop/options.h"
+#if defined(riscos)
+#include "riscos/options.h"
+#elif defined(nsgtk)
+#include "gtk/options.h"
+#elif defined(nsbeos)
+#include "beos/options.h"
+#elif defined(nsamiga)
+#include "amiga/options.h"
+#elif defined(nsframebuffer)
+#include "framebuffer/options.h"
+#elif defined(nsatari)
+#include "atari/options.h"
+#elif defined(nsmonkey)
+#include "monkey/options.h"
+#endif
+
+#undef NSOPTION_BOOL
+#undef NSOPTION_STRING
+#undef NSOPTION_INTEGER
+#undef NSOPTION_UINT
+#undef NSOPTION_COLOUR
+
+
+
+enum { OPTION_HTTP_PROXY_AUTH_NONE = 0,
+       OPTION_HTTP_PROXY_AUTH_BASIC = 1,
+       OPTION_HTTP_PROXY_AUTH_NTLM = 2 };
+
+#define DEFAULT_MARGIN_TOP_MM 10
+#define DEFAULT_MARGIN_BOTTOM_MM 10
+#define DEFAULT_MARGIN_LEFT_MM 10
+#define DEFAULT_MARGIN_RIGHT_MM 10
+#define DEFAULT_EXPORT_SCALE 0.7
+
+#ifndef DEFAULT_REFLOW_PERIOD
+/** Default reflow time in cs */
+#define DEFAULT_REFLOW_PERIOD 25
+#endif
+
+/** The options type. */
+enum nsoption_type_e {
+	OPTION_BOOL, /**< Option is a boolean. */
+	OPTION_INTEGER, /**< Option is an integer. */
+	OPTION_UINT, /**< Option is an unsigned integer */
+	OPTION_STRING, /**< option is a heap allocated string. */
+	OPTION_COLOUR /**< Option  is a netsurf colour. */
+};
+
+struct nsoption_s {
+	const char *key;
+	int key_len;
+	enum nsoption_type_e type;
+	union {
+		bool b;
+		int i;
+		unsigned int u;
+		char *s;
+		const char *cs;
+		colour c;
+	} value;
+};
+
+/* construct the option enumeration */
+#define NSOPTION_BOOL(NAME, DEFAULT) NSOPTION_##NAME,
+#define NSOPTION_STRING(NAME, DEFAULT) NSOPTION_##NAME,
+#define NSOPTION_INTEGER(NAME, DEFAULT) NSOPTION_##NAME,
+#define NSOPTION_UINT(NAME, DEFAULT) NSOPTION_##NAME,
+#define NSOPTION_COLOUR(NAME, DEFAULT) NSOPTION_##NAME,
+
+enum nsoption_e {
+#include "desktop/options.h"
+#if defined(riscos)
+#include "riscos/options.h"
+#elif defined(nsgtk)
+#include "gtk/options.h"
+#elif defined(nsbeos)
+#include "beos/options.h"
+#elif defined(nsamiga)
+#include "amiga/options.h"
+#elif defined(nsframebuffer)
+#include "framebuffer/options.h"
+#elif defined(nsatari)
+#include "atari/options.h"
+#elif defined(nsmonkey)
+#include "monkey/options.h"
+#endif
+	NSOPTION_LISTEND /* end of list */
+};
+
+#undef NSOPTION_BOOL
+#undef NSOPTION_STRING
+#undef NSOPTION_INTEGER
+#undef NSOPTION_UINT
+#undef NSOPTION_COLOUR
+
+/**
+ * global active option table.
+ */
+extern struct nsoption_s *nsoptions;
+
+/**
+ * global default option table.
+ */
+extern struct nsoption_s *nsoptions_default;
+
+/**
+ * default setting callback.
+ */
+typedef nserror(nsoption_set_default_t)(struct nsoption_s *defaults);
+
+
+/**
+ * Initialise option system.
+ *
+ * @param set_default callback to allow the customisation of the default
+ *                    options.
+ * @param ppots pointer to update to get options table or NULL.
+ * @param pdefs pointer to update to get default options table or NULL.
+ * @return The error status
+ */
+nserror nsoption_init(nsoption_set_default_t *set_default, struct nsoption_s **popts, struct nsoption_s **pdefs);
+
+
+/**
+ * Finalise option system
+ *
+ * Releases all resources allocated in the initialisation.
+ *
+ * @param opts the options table or NULL to use global table.
+ * @param defs the default options table to use or NULL to use global table
+ * return The error status
+ */
+nserror nsoption_finalise(struct nsoption_s *opts, struct nsoption_s *defs);
+
+
+/**
+ * Read choices file and set them in the passed table
+ *
+ * @param path The path to read the file from
+ * @param opts The options table to enerate values from or NULL to use global
+ * @return The error status
+ */
+nserror nsoption_read(const char *path, struct nsoption_s *opts);
+
+
+/**
+ * Write options that have changed from the defaults to a file.
+ *
+ * The \a nsoption_dump can be used to output all entries not just
+ * changed ones.
+ *
+ * @param path The path to read the file from
+ * @param opts The options table to enerate values from or NULL to use global
+ * @param defs The default table to use or NULL to use global
+ * @return The error status
+ */
+nserror nsoption_write(const char *path, struct nsoption_s *opts, struct nsoption_s *defs);
+
+
+/**
+ * Write all options to a stream.
+ *
+ * @param outf The stream to write to
+ * @param opts The options table to enerate values from or NULL to use global
+ * @return The error status
+ */
+nserror nsoption_dump(FILE *outf, struct nsoption_s *opts);
+
+
+/**
+ * Process commandline and set options approriately.
+ *
+ * @param pargc Pointer to the size of the argument vector.
+ * @param argv The argument vector.
+ * @param opts The options table to enerate values from or NULL to use global
+ * @return The error status
+ */
+nserror nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts);
+
+
+/**
+ * Fill a buffer with an option using a format.
+ *
+ * The format string is copied into the output buffer with the
+ * following replaced:
+ * %k - The options key
+ * %t - The options type
+ * %V - value (HTML formatting)
+ * %v - value (plain formatting)
+ * %p - provenance either "user" or "default"
+ *
+ * @param string The buffer in which to place the results.
+ * @param size The size of the string buffer.
+ * @param option The option .
+ * @param fmt The format string.
+ * @return The number of bytes written to \a string or -1 on error
+ */
+int nsoption_snoptionf(char *string, size_t size, enum nsoption_e option, const char *fmt);
+
+
+/**
+ * Get the value of a boolean option.
+ *
+ * Gets the value of an option assuming it is a boolean type.
+ * @note option type is unchecked so care must be taken in caller.
+ */
+#define nsoption_bool(OPTION) (nsoptions[NSOPTION_##OPTION].value.b)
+
+
+/**
+ * Get the value of an integer option.
+ *
+ * Gets the value of an option assuming it is a integer type.
+ * @note option type is unchecked so care must be taken in caller.
+ */
+#define nsoption_int(OPTION) (nsoptions[NSOPTION_##OPTION].value.i)
+
+
+/**
+ * Get the value of an unsigned integer option.
+ *
+ * Gets the value of an option assuming it is a integer type.
+ * @note option type is unchecked so care must be taken in caller.
+ */
+#define nsoption_uint(OPTION) (nsoptions[NSOPTION_##OPTION].value.u)
+
+
+/**
+ * Get the value of a string option.
+ *
+ * Gets the value of an option assuming it is a string type.
+ * @note option type is unchecked so care must be taken in caller.
+ */
+#define nsoption_charp(OPTION) (nsoptions[NSOPTION_##OPTION].value.s)
+
+
+/**
+ * Get the value of a netsurf colour option.
+ *
+ * Gets the value of an option assuming it is a colour type.
+ * @note option type is unchecked so care must be taken in caller.
+ */
+#define nsoption_colour(OPTION) (nsoptions[NSOPTION_##OPTION].value.c)
+
+
+/** set a boolean option in the default table */
+#define nsoption_set_bool(OPTION, VALUE) nsoptions[NSOPTION_##OPTION].value.b = VALUE
+
+
+/** set an integer option in the default table */
+#define nsoption_set_int(OPTION, VALUE) nsoptions[NSOPTION_##OPTION].value.i = VALUE
+
+
+/** set a colour option in the default table */
+#define nsoption_set_colour(OPTION, VALUE) nsoptions[NSOPTION_##OPTION].value.c = VALUE
+
+
+/**
+ * Set string option in specified table.
+ *
+ * Sets the string option to the value given freeing any resources
+ * currently allocated to the option. If the passed string is empty it
+ * is converted to the NULL value.
+ *
+ * @param opts The table to set option in
+ * @param option_idx The option
+ * @param s The string to set. This is used directly and not copied.
+ */
+nserror nsoption_set_tbl_charp(struct nsoption_s *opts, enum nsoption_e option_idx, char *s);
+
+/** set string option in default table */
+#define nsoption_set_charp(OPTION, VALUE) \
+	nsoption_set_tbl_charp(nsoptions, NSOPTION_##OPTION, VALUE)
+
+/** set string option in default table if currently unset */
+#define nsoption_setnull_charp(OPTION, VALUE)				\
+	do {								\
+		if (nsoptions[NSOPTION_##OPTION].value.s == NULL) {	\
+			nsoption_set_tbl_charp(nsoptions, NSOPTION_##OPTION, VALUE); \
+		} else {						\
+			free(VALUE);					\
+		}							\
+	} while (0)
+
+#endif
diff --git a/windows/Makefile.target b/windows/Makefile.target
index defb765..f490795 100644
--- a/windows/Makefile.target
+++ b/windows/Makefile.target
@@ -67,7 +67,7 @@ S_RESOURCES := windows_resource.o
 S_WINDOWS := main.c window.c gui.c drawable.c misc.c plot.c findfile.c	\
 	  font.c bitmap.c about.c prefs.c download.c filetype.c		\
 	  localhistory.c login.c schedule.c thumbnail.c tree.c		\
-	  windbg.c system_colour.c
+	  windbg.c
 S_WINDOWS := $(addprefix windows/,$(S_WINDOWS)) 
 
 # This is the final source build list
diff --git a/windows/font.c b/windows/font.c
index 564a7de..c99cec7 100644
--- a/windows/font.c
+++ b/windows/font.c
@@ -28,7 +28,7 @@
 
 #include "css/css.h"
 #include "render/font.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/utf8.h"
 
 #include "windows/font.h"
diff --git a/windows/gui.c b/windows/gui.c
index e318f3a..f8d57fd 100644
--- a/windows/gui.c
+++ b/windows/gui.c
@@ -36,7 +36,7 @@
 #include "desktop/history_core.h"
 #include "desktop/mouse.h"
 #include "desktop/netsurf.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/plotters.h"
 #include "desktop/textinput.h"
 #include "render/html.h"
@@ -931,7 +931,7 @@ nsws_window_command(HWND hwnd,
 		nsoption_set_int(window_y, r.top);
 		nsoption_set_int(window_width, r.right - r.left);
 		nsoption_set_int(window_height, r.bottom - r.top);
-		nsoption_write(options_file_location);
+		nsoption_write(options_file_location, NULL, NULL);
 		break;
 	}
 
diff --git a/windows/main.c b/windows/main.c
index 19f71dd..69a152d 100644
--- a/windows/main.c
+++ b/windows/main.c
@@ -24,7 +24,7 @@
 #include <windows.h>
 
 #include "desktop/gui.h"
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "desktop/browser.h"
 #include "utils/utils.h"
 #include "utils/log.h"
@@ -66,9 +66,9 @@ void gui_quit(void)
 }
 
 /** 
- * Ensures output stdio stream is available
+ * Ensures output logging stream is available
  */
-bool nslog_ensure(FILE *fptr)
+static bool nslog_ensure(FILE *fptr)
 {
 	/* mwindows compile flag normally invalidates standard io unless
 	 *  already redirected 
@@ -80,13 +80,20 @@ bool nslog_ensure(FILE *fptr)
 	return true;
 }
 
-/* Documented in desktop/options.h */
-void gui_options_init_defaults(void)
+/**
+ * Set option defaults for framebuffer frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
 {
 	/* Set defaults for absent option strings */
 
 	/* ensure homepage option has a default */
 	nsoption_setnull_charp(homepage_url, strdup(NETSURF_HOMEPAGE));
+
+	return NSERROR_OK;
 }
 
 /**
@@ -132,14 +139,31 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
 
 	respaths = nsws_init_resource("${APPDATA}\\NetSurf:${HOME}\\.netsurf:${NETSURFRES}:${PROGRAMFILES}\\NetSurf\\NetSurf\\:"NETSURF_WINDOWS_RESPATH);
 
-	messages = filepath_find(respaths, "messages");
 
 	options_file_location = filepath_find(respaths, "preferences");
 
-	/* initialise netsurf */
-	netsurf_init(&argc, &argv, options_file_location, messages);
+	/* initialise logging - not fatal if it fails but not much we
+	 * can do about it 
+	 */
+	nslog_init(nslog_ensure, &argc, argv);
+
+	/* user options setup */
+	ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+	if (ret != NSERROR_OK) {
+		die("Options failed to initialise");
+	}
+	nsoption_read(options_file_location, NULL);
+	nsoption_commandline(&argc, argv, NULL);
 
+	/* common initialisation */
+	messages = filepath_find(respaths, "messages");
+	ret = netsurf_init(messages);
 	free(messages);
+	if (ret != NSERROR_OK) {
+		free(options_file_location);
+		LOG(("NetSurf failed to initialise"));
+		return 1;
+	}
 
 	ret = nsws_create_main_class(hInstance);
 	ret = nsws_create_drawable_class(hInstance);
diff --git a/windows/prefs.c b/windows/prefs.c
index 577c2a5..e933cc1 100644
--- a/windows/prefs.c
+++ b/windows/prefs.c
@@ -21,7 +21,7 @@
 #include <windows.h>
 #include <commctrl.h>
 
-#include "desktop/options.h"
+#include "utils/nsoption.h"
 #include "utils/log.h"
 #include "utils/messages.h"
 #include "utils/utils.h"
@@ -583,7 +583,7 @@ static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
 		/* advert blocking */
 		sub = GetDlgItem(hwnd, IDC_PREFS_ADVERTS);
 		SendMessage(sub, BM_SETCHECK, 
-			    (WPARAM) ((nsoption_bool(block_ads)) ? 
+			    (WPARAM) ((nsoption_bool(block_advertisements)) ? 
 				  BST_CHECKED : BST_UNCHECKED), 0);
 
 		/* Referrer sending */
@@ -615,7 +615,7 @@ static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
 			nsoption_set_bool(suppress_images,
 					  (IsDlgButtonChecked(hwnd, IDC_PREFS_IMAGES) == BST_CHECKED) ? true : false);
 
-			nsoption_set_bool(block_ads, (IsDlgButtonChecked(hwnd, 
+			nsoption_set_bool(block_advertisements, (IsDlgButtonChecked(hwnd, 
 									 IDC_PREFS_ADVERTS) == BST_CHECKED) ? true : false);
 
 			nsoption_set_bool(send_referer, (IsDlgButtonChecked(hwnd, 
@@ -675,7 +675,6 @@ void nsws_prefs_dialog_init(HINSTANCE hinst, HWND parent)
 		win_perror("PropertySheet");
 	} else if (ret > 0) {
 		/* user saved changes */
-		nsoption_write(options_file_location);
+		nsoption_write(options_file_location, NULL, NULL);
 	}
-
 }
diff --git a/windows/system_colour.c b/windows/system_colour.c
deleted file mode 100644
index 6c1fd81..0000000
--- a/windows/system_colour.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince at netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf 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; version 2 of the License.
- *
- * NetSurf 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, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * System colour handling
- *
- */
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "desktop/gui.h"
-#include "desktop/options.h"
-
-struct gui_system_colour_ctx {
-	const char *name;
-	int length;
-	css_color colour;
-	colour *option_colour;
-	lwc_string *lwcstr;
-};
-
-static struct gui_system_colour_ctx colour_list[] = { 
-	{ 
-		"ActiveBorder", 
-		SLEN("ActiveBorder"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ActiveBorder), 
-		NULL 
-	}, { 
-		"ActiveCaption", 
-		SLEN("ActiveCaption"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ActiveCaption), 
-		NULL 
-	}, { 
-		"AppWorkspace", 
-		SLEN("AppWorkspace"), 
-		0xffeeeeee, 
-		&nsoption_charp(sys_colour_AppWorkspace), 
-		NULL 
-	}, { 
-		"Background", 
-		SLEN("Background"), 
-		0xff0000aa, 
-		&nsoption_charp(sys_colour_Background), 
-		NULL 
-	}, {
-		"ButtonFace", 
-		SLEN("ButtonFace"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ButtonFace), 
-		NULL 
-	}, {
-		"ButtonHighlight", 
-		SLEN("ButtonHighlight"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ButtonHighlight), 
-		NULL
-	}, {
-		"ButtonShadow", 
-		SLEN("ButtonShadow"), 
-		0xffbbbbbb, 
-		&nsoption_charp(sys_colour_ButtonShadow), 
-		NULL 
-	}, {
-		"ButtonText", 
-		SLEN("ButtonText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_ButtonText), 
-		NULL 
-	}, {
-		"CaptionText", 
-		SLEN("CaptionText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_CaptionText), 
-		NULL 
-	}, {
-		"GrayText", 
-		SLEN("GrayText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_GrayText), 
-		NULL 
-	}, {
-		"Highlight", 
-		SLEN("Highlight"), 
-		0xff0000ee, 
-		&nsoption_charp(sys_colour_Highlight), 
-		NULL 
-	}, {
-		"HighlightText", 
-		SLEN("HighlightText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_HighlightText), 
-		NULL 
-	}, {
-		"InactiveBorder", 
-		SLEN("InactiveBorder"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveBorder), 
-		NULL 
-	}, {
-		"InactiveCaption", 
-		SLEN("InactiveCaption"), 
-		0xffffffff, 
-		&nsoption_charp(sys_colour_InactiveCaption), 
-		NULL 
-	}, {
-		"InactiveCaptionText", 
-		SLEN("InactiveCaptionText"), 
-		0xffcccccc, 
-		&nsoption_charp(sys_colour_InactiveCaptionText), 
-		NULL 
-	}, {
-		"InfoBackground", 
-		SLEN("InfoBackground"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_InfoBackground), 
-		NULL 
-	}, {
-		"InfoText", 
-		SLEN("InfoText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_InfoText), 
-		NULL 
-	}, {
-		"Menu", 
-		SLEN("Menu"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Menu), 
-		NULL 
-	}, {
-		"MenuText", 
-		SLEN("MenuText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_MenuText), 
-		NULL 
-	}, {
-		"Scrollbar", 
-		SLEN("Scrollbar"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Scrollbar), 
-		NULL 
-	}, {
-		"ThreeDDarkShadow", 
-		SLEN("ThreeDDarkShadow"), 
-		0xff555555, 
-		&nsoption_charp(sys_colour_ThreeDDarkShadow), 
-		NULL 
-	}, {
-		"ThreeDFace", 
-		SLEN("ThreeDFace"), 
-		0xffdddddd, 
-		&nsoption_charp(sys_colour_ThreeDFace), 
-		NULL 
-	}, {
-		"ThreeDHighlight", 
-		SLEN("ThreeDHighlight"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_ThreeDHighlight), 
-		NULL 
-	}, {
-		"ThreeDLightShadow", 
-		SLEN("ThreeDLightShadow"), 
-		0xff999999, 
-		&nsoption_charp(sys_colour_ThreeDLightShadow), 
-		NULL 
-	}, {
-		"ThreeDShadow", 
-		SLEN("ThreeDShadow"), 
-		0xff777777, 
-		&nsoption_charp(sys_colour_ThreeDShadow), 
-		NULL 
-	}, {
-		"Window", 
-		SLEN("Window"), 
-		0xffaaaaaa, 
-		&nsoption_charp(sys_colour_Window), 
-		NULL 
-	}, {
-		"WindowFrame", 
-		SLEN("WindowFrame"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowFrame), 
-		NULL 
-	}, {
-		
-		"WindowText", 
-		SLEN("WindowText"), 
-		0xff000000, 
-		&nsoption_charp(sys_colour_WindowText), 
-		NULL 
-	},
-
-};
-
-#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
-
-static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
-
-
-bool gui_system_colour_init(void)
-{
-	unsigned int ccount;
-
-	if (gui_system_colour_pw != NULL) 
-		return false;
-
-	/* Intern colour strings */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_intern_string(colour_list[ccount].name, 
-				      colour_list[ccount].length, 
-				      &(colour_list[ccount].lwcstr)) != lwc_error_ok) {
-			return false;
-		}
-	}
-
-	/* pull in options if set (ie not transparent) */
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (*(colour_list[ccount].option_colour) != 0) {
-			colour_list[ccount].colour = *(colour_list[ccount].option_colour);
-		}
-	}
-
-	gui_system_colour_pw = colour_list;
-	
-	return true;
-}
-
-void gui_system_colour_finalize(void)
-{
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		lwc_string_unref(colour_list[ccount].lwcstr);
-	}
-}
-
-colour gui_system_colour_char(const char *name)
-{
-	colour ret = 0xff00000;
-	unsigned int ccount;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (strcmp(name, colour_list[ccount].name) == 0) {
-			ret = colour_list[ccount].colour;
-			break;
-		}
-	}
-	return ret;
-}
-
-css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
-{
-	unsigned int ccount;
-	bool match;
-
-	for (ccount = 0; ccount < colour_list_len; ccount++) {
-		if (lwc_string_caseless_isequal(name, 
-				colour_list[ccount].lwcstr,
-				&match) == lwc_error_ok && match) {
-			*colour = colour_list[ccount].colour;
-			return CSS_OK;
-		}
-	}	
-
-	return CSS_INVALID;
-}


-- 
NetSurf Browser



More information about the netsurf-commits mailing list