changeset 48:224c9f547b39

Implemented "Load Images" in the page menu and cleaned up html.hh.
author jcid
date Wed, 14 Nov 2007 22:27:26 +0100
parents 1b7243d62913
children 63610ed24f7b
files ChangeLog src/bw.c src/bw.h src/html.cc src/html.hh src/menu.cc src/menu.hh src/plain.cc src/uicmd.cc src/uicmd.hh
diffstat 10 files changed, 409 insertions(+), 310 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Nov 14 15:32:16 2007 +0100
+++ b/ChangeLog	Wed Nov 14 22:27:26 2007 +0100
@@ -58,6 +58,7 @@
 +- Fixed a problem with locally-installed dpis.
  - Added code for optional image loading (nice interface) very advanced!
  - Added an experimental gzip decoder! 
+ - Implemented "Load Images" in the page menu and cleaned up html.hh.
    Patch: place, Jorge Arellano
 +- Fixed a va_list-related SEGFAULT on 64bit-arch in dStr_vsprintfa().
    Added const declarations in html parser.
--- a/src/bw.c	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/bw.c	Wed Nov 14 22:27:26 2007 +0100
@@ -71,6 +71,7 @@
    bw->NumImages = 0;
    bw->NumImagesGot = 0;
    bw->PageUrls = dList_new(8);
+   bw->Docs = dList_new(8);
 
    bw->question_dialog_data = NULL;
 
@@ -96,6 +97,7 @@
 
          dList_free(bw->RootClients);
          dList_free(bw->ImageClients);
+         dList_free(bw->Docs);
 
          for (j = 0; j < dList_length(bw->PageUrls); ++j)
             a_Url_free(dList_nth_data(bw->PageUrls, j));
@@ -194,7 +196,7 @@
    }
 }
 
-/*- PageUrls ---------------------------------------------------------------*/
+/*- Page -------------------------------------------------------------------*/
 /*
  * Add an URL to the browser window's list.
  * This helps us keep track of page-requested URLs so that it's
@@ -209,6 +211,28 @@
    }
 }
 
+/*
+ * Add a document to the browser window's list.
+ */
+void a_Bw_add_doc(BrowserWindow *bw, void *vdoc)
+{
+   dReturn_if_fail ( bw != NULL && vdoc != NULL);
+
+   dList_append(bw->Docs, vdoc);
+}
+
+/*
+ * Remove a document from the bw's list
+ */
+void a_Bw_remove_doc(BrowserWindow *bw, void *vdoc)
+{
+   void *data;
+
+   if ((data = dList_find(bw->Docs, vdoc))) {
+      dList_remove_fast(bw->Docs, data);
+   }
+}
+
 /*- Cleanup ----------------------------------------------------------------*/
 /*
  * Empty RootClients, ImageClients and PageUrls lists and
--- a/src/bw.h	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/bw.h	Wed Nov 14 22:27:26 2007 +0100
@@ -24,9 +24,12 @@
 
    /* All the rendering is done by this.
     * It is defined as a void pointer to avoid C++ in this structure.
-    * C++ sources have to include browser.h and cast it into an object. */
+    * C++ sources have to include "dw/core.hh" and cast it into an object. */
    void *render_layout;
 
+   /* Root document(s). Currently only used by DilloHtml */
+   Dlist *Docs;
+
    /* A list of active cache clients in the window (The primary Key) */
    Dlist *RootClients;
    /* Image Keys for all active connections in the window */
@@ -82,6 +85,8 @@
 int a_Bw_remove_client(BrowserWindow *bw, int ClientKey);
 void a_Bw_close_client(BrowserWindow *bw, int ClientKey);
 void a_Bw_stop_clients(BrowserWindow *bw, int flags);
+void a_Bw_add_doc(BrowserWindow *bw, void *vdoc);
+void a_Bw_remove_doc(BrowserWindow *bw, void *vdoc);
 void a_Bw_add_url(BrowserWindow *bw, const DilloUrl *Url);
 void a_Bw_cleanup(BrowserWindow *bw);
 
--- a/src/html.cc	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/html.cc	Wed Nov 14 22:27:26 2007 +0100
@@ -13,14 +13,9 @@
  * Dillo HTML parsing routines
  */
 
-/* Undefine if you want to unroll tables. For instance for PDAs */
-#define USE_TABLES
-
-/* Define to 1 to ignore white space immediately after an open tag,
- * and immediately before a close tag. */
-#define SGML_SPCDEL 0
-
-
+/*-----------------------------------------------------------------------------
+ * Includes
+ *---------------------------------------------------------------------------*/
 #include <ctype.h>      /* for isspace and tolower */
 #include <string.h>     /* for memcpy and memmove */
 #include <stdlib.h>
@@ -33,22 +28,20 @@
 #define DEBUG_LEVEL 10
 #include "debug.h"
 
+#include "bw.h"         /* for BrowserWindow */
 #include "msg.h"
 #include "binaryconst.h"
 #include "colors.h"
 
 #include "uicmd.hh"
-
-#define dillo_dbg_rendering 0
-
 #include "history.h"
 #include "nav.h"
 #include "menu.hh"
 #include "prefs.h"
 #include "misc.h"
 #include "capi.h"
-
 #include "html.hh"
+
 #include "dw/textblock.hh"
 #include "dw/bullet.hh"
 #include "dw/table.hh"
@@ -57,16 +50,18 @@
 #include "dw/image.hh"
 #include "dw/ruler.hh"
 
-
-using namespace dw;
-using namespace dw::core;
-using namespace dw::core::ui;
-using namespace dw::core::style;
-
-typedef void (*TagOpenFunct) (DilloHtml *Html, const char *Tag, int Tagsize);
-typedef void (*TagCloseFunct) (DilloHtml *Html, int TagIdx);
+/*-----------------------------------------------------------------------------
+ * Defines 
+ *---------------------------------------------------------------------------*/
+/* Undefine if you want to unroll tables. For instance for PDAs */
+#define USE_TABLES
+
+/* Define to 1 to ignore white space immediately after an open tag,
+ * and immediately before a close tag. */
+#define SGML_SPCDEL 0
 
 #define TAB_SIZE 8
+#define dillo_dbg_rendering 0
 
 // Dw to Textblock
 #define DW2TB(dw)  ((Textblock*)dw)
@@ -77,6 +72,276 @@
 // Top of the parsing stack
 #define S_TOP(html)  (html->stack->getRef(html->stack->size()-1))
 
+/*-----------------------------------------------------------------------------
+ * Name spaces
+ *---------------------------------------------------------------------------*/
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::ui;
+using namespace dw::core::style;
+
+/*-----------------------------------------------------------------------------
+ * Typedefs
+ *---------------------------------------------------------------------------*/
+class DilloHtml;
+typedef void (*TagOpenFunct) (DilloHtml *Html, const char *Tag, int Tagsize);
+typedef void (*TagCloseFunct) (DilloHtml *Html, int TagIdx);
+typedef struct _DilloLinkImage   DilloLinkImage;
+typedef struct _DilloHtmlClass   DilloHtmlClass;
+typedef struct _DilloHtmlState   DilloHtmlState;
+typedef struct _DilloHtmlForm    DilloHtmlForm;
+typedef struct _DilloHtmlOption  DilloHtmlOption;
+typedef struct _DilloHtmlSelect  DilloHtmlSelect;
+typedef struct _DilloHtmlInput   DilloHtmlInput;
+
+typedef enum {
+   DT_NONE,           
+   DT_HTML,           
+   DT_XHTML
+} DilloHtmlDocumentType;
+
+typedef enum {
+   DILLO_HTML_PARSE_MODE_INIT = 0,
+   DILLO_HTML_PARSE_MODE_STASH,
+   DILLO_HTML_PARSE_MODE_STASH_AND_BODY,
+   DILLO_HTML_PARSE_MODE_VERBATIM,
+   DILLO_HTML_PARSE_MODE_BODY,
+   DILLO_HTML_PARSE_MODE_PRE
+} DilloHtmlParseMode;
+
+typedef enum {
+   SEEK_ATTR_START,
+   MATCH_ATTR_NAME,
+   SEEK_TOKEN_START,
+   SEEK_VALUE_START,
+   SKIP_VALUE,
+   GET_VALUE,
+   FINISHED
+} DilloHtmlTagParsingState;
+
+typedef enum {
+   HTML_LeftTrim      = 1 << 0,
+   HTML_RightTrim     = 1 << 1,
+   HTML_ParseEntities = 1 << 2
+} DilloHtmlTagParsingFlags;
+
+typedef enum {
+   DILLO_HTML_TABLE_MODE_NONE,  /* no table at all */
+   DILLO_HTML_TABLE_MODE_TOP,   /* outside of <tr> */
+   DILLO_HTML_TABLE_MODE_TR,    /* inside of <tr>, outside of <td> */
+   DILLO_HTML_TABLE_MODE_TD     /* inside of <td> */
+} DilloHtmlTableMode;
+
+typedef enum {
+   HTML_LIST_NONE,
+   HTML_LIST_UNORDERED,
+   HTML_LIST_ORDERED
+} DilloHtmlListMode;
+
+typedef enum {
+   DILLO_HTML_METHOD_UNKNOWN,
+   DILLO_HTML_METHOD_GET,
+   DILLO_HTML_METHOD_POST
+} DilloHtmlMethod;
+
+typedef enum {
+   DILLO_HTML_ENC_URLENCODING
+} DilloHtmlEnc;
+
+typedef enum {
+   DILLO_HTML_INPUT_UNKNOWN,
+   DILLO_HTML_INPUT_TEXT,
+   DILLO_HTML_INPUT_PASSWORD,
+   DILLO_HTML_INPUT_CHECKBOX,
+   DILLO_HTML_INPUT_RADIO,
+   DILLO_HTML_INPUT_IMAGE,
+   DILLO_HTML_INPUT_FILE,
+   DILLO_HTML_INPUT_BUTTON,
+   DILLO_HTML_INPUT_HIDDEN,
+   DILLO_HTML_INPUT_SUBMIT,
+   DILLO_HTML_INPUT_RESET,
+   DILLO_HTML_INPUT_BUTTON_SUBMIT,
+   DILLO_HTML_INPUT_BUTTON_RESET,
+   DILLO_HTML_INPUT_SELECT,
+   DILLO_HTML_INPUT_SEL_LIST,
+   DILLO_HTML_INPUT_TEXTAREA,
+   DILLO_HTML_INPUT_INDEX
+} DilloHtmlInputType;
+
+typedef enum {
+   IN_NONE        = 0,
+   IN_HTML        = 1 << 0,
+   IN_HEAD        = 1 << 1,
+   IN_BODY        = 1 << 2,
+   IN_FORM        = 1 << 3,
+   IN_SELECT      = 1 << 4,
+   IN_TEXTAREA    = 1 << 5,
+   IN_MAP         = 1 << 6,
+   IN_PRE         = 1 << 7,
+   IN_BUTTON      = 1 << 8
+} DilloHtmlProcessingState;
+
+/*-----------------------------------------------------------------------------
+ * Data Structures
+ *---------------------------------------------------------------------------*/
+struct _DilloLinkImage {
+   DilloUrl *url;
+   DilloImage *image;
+};
+
+struct _DilloHtmlState {
+   char *tag_name;
+   //DwStyle *style, *table_cell_style;
+   dw::core::style::Style *style, *table_cell_style;
+   DilloHtmlParseMode parse_mode;
+   DilloHtmlTableMode table_mode;
+   bool_t cell_text_align_set;
+   DilloHtmlListMode list_type;
+   int list_number;
+
+   /* TagInfo index for the tag that's being processed */
+   int tag_idx;
+
+   dw::core::Widget *textblock, *table;
+
+   /* This is used to align list items (especially in enumerated lists) */
+   dw::core::Widget *ref_list_item;
+
+   /* This makes image processing faster than a function
+      a_Dw_widget_get_background_color. */
+   int32_t current_bg_color;
+
+   /* This is used for list items etc; if it is set to TRUE, breaks
+      have to be "handed over" (see Html_add_indented and
+      Html_eventually_pop_dw). */
+   bool_t hand_over_break;
+};
+
+struct _DilloHtmlForm {
+   DilloHtmlMethod method;
+   DilloUrl *action;
+   DilloHtmlEnc enc;
+
+   misc::SimpleVector<DilloHtmlInput> *inputs;
+
+   int num_entry_fields;
+   int num_submit_buttons;
+
+   form::Form *form_receiver;
+};
+
+struct _DilloHtmlOption {
+   //GtkWidget *menuitem;
+   char *value;
+   bool_t init_val;
+};
+
+struct _DilloHtmlSelect {
+   //GtkWidget *menu;
+   int size;
+
+   DilloHtmlOption *options;
+   int num_options;
+   int num_options_max;
+};
+
+struct _DilloHtmlInput {
+   DilloHtmlInputType type;
+   void *widget;      /* May be a FLTKWidget or a Dw Widget. */
+   void *embed;       /* May be NULL */
+   char *name;
+   char *init_str;    /* note: some overloading - for buttons, init_str
+                         is simply the value of the button; for text
+                         entries, it is the initial value */
+   DilloHtmlSelect *select;
+   bool_t init_val;   /* only meaningful for buttons */
+};
+
+/*-----------------------------------------------------------------------------
+ * Classes
+ *---------------------------------------------------------------------------*/
+class DilloHtml {
+private:
+   class HtmlLinkReceiver: public dw::core::Widget::LinkReceiver {
+   public:
+      DilloHtml *html;
+
+      bool enter (dw::core::Widget *widget, int link, int img, int x, int y);
+      bool press (dw::core::Widget *widget, int link, int img, int x, int y,
+                  dw::core::EventButton *event);
+      bool click (dw::core::Widget *widget, int link, int img, int x, int y,
+                  dw::core::EventButton *event);
+   };
+   HtmlLinkReceiver linkReceiver;
+
+public:  //BUG: for now everything is public
+
+   BrowserWindow *bw;
+   DilloUrl *base_url;
+   dw::core::Widget *dw;    /* this is duplicated in the stack */
+
+   /* -------------------------------------------------------------------*/
+   /* Variables required at parsing time                                 */
+   /* -------------------------------------------------------------------*/
+   char *Start_Buf;
+   size_t Start_Ofs;
+   size_t CurrTagOfs;
+   size_t OldTagOfs, OldTagLine;
+
+   DilloHtmlDocumentType DocType; /* as given by DOCTYPE tag */
+   float DocTypeVersion;          /* HTML or XHTML version number */
+
+   misc::SimpleVector<DilloHtmlState> *stack;
+
+   int InFlags; /* tracks which elements we are in */
+
+   Dstr *Stash;
+   bool_t StashSpace;
+
+   char *SPCBuf;          /* Buffer for white space */
+
+   int pre_column;        /* current column, used in PRE tags with tabs */
+   bool_t PreFirstChar;   /* used to skip the first CR or CRLF in PRE tags */
+   bool_t PrevWasCR;      /* Flag to help parsing of "\r\n" in PRE tags */
+   bool_t PrevWasOpenTag; /* Flag to help deferred parsing of white space */
+   bool_t SPCPending;     /* Flag to help deferred parsing of white space */
+   bool_t InVisitedLink;  /* used to 'contrast_visited_colors' */
+   bool_t ReqTagClose;    /* Flag to help handling bad-formed HTML */
+   bool_t CloseOneTag;    /* Flag to help Html_tag_cleanup_at_close() */
+   bool_t TagSoup;        /* Flag to enable the parser's cleanup functions */
+   char *NameVal;         /* used for validation of "NAME" and "ID" in <A> */
+
+   /* element counters: used for validation purposes */
+   uchar_t Num_HTML, Num_HEAD, Num_BODY, Num_TITLE;
+
+   Dstr *attr_data;       /* Buffer for attribute value */
+
+   /* -------------------------------------------------------------------*/
+   /* Variables required after parsing (for page functionality)          */
+   /* -------------------------------------------------------------------*/
+   misc::SimpleVector<DilloHtmlForm> *forms;
+   misc::SimpleVector<DilloUrl*> *links;
+   misc::SimpleVector<DilloLinkImage*> *images;
+   //DwImageMapList maps;
+
+   int32_t link_color;
+   int32_t visited_color;
+
+private:
+   void initDw();  /* Used by the constructor */
+
+public:
+   DilloHtml(BrowserWindow *bw, const DilloUrl *url);
+   ~DilloHtml();
+   void connectSignals(dw::core::Widget *dw);
+   void write(char *Buf, int BufSize, int Eof);
+   void closeParser(int ClientKey);
+   int formNew(DilloHtmlMethod method, const DilloUrl *action,
+               DilloHtmlEnc enc);
+   void loadImages (const DilloUrl *pattern);
+};
+
+
 /*
  * Exported function with C linkage.
  */
@@ -84,9 +349,9 @@
 void *a_Html_text(const char *type, void *P, CA_Callback_t *Call,void **Data);
 }
 
-/*
+/*-----------------------------------------------------------------------------
  * Forward declarations
- */
+ *---------------------------------------------------------------------------*/
 static const char *Html_get_attr(DilloHtml *html,
                                  const char *tag,
                                  int tagsize,
@@ -121,11 +386,9 @@
 static int Html_tag_index(const char *tag);
 static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx);
 
-
-/*
+/*-----------------------------------------------------------------------------
  * Local Data
- */
-
+ *---------------------------------------------------------------------------*/
 /* The following array of font sizes has to be _strictly_ crescent */
 static const int FontSizes[] = {8, 10, 12, 14, 18, 24};
 static const int FontSizesNum = 6;
@@ -142,6 +405,13 @@
 } TagInfo;
 extern const TagInfo Tags[];
 
+
+/*-----------------------------------------------------------------------------
+ *-----------------------------------------------------------------------------
+ * Main Code
+ *-----------------------------------------------------------------------------
+ *---------------------------------------------------------------------------*/
+
 /*
  * Return the line number of the tag being processed by the parser.
  */
@@ -232,6 +502,15 @@
    delete ((DilloHtml*)data);
 }
 
+/*
+ * Used bye the "Load images" page menuitem.
+ */ 
+void a_Html_load_images(void *v_html, DilloUrl *pattern)
+{
+   DilloHtml *html = (DilloHtml*)v_html;
+
+   html->loadImages(pattern);
+}
 
 /*
  * Set the URL data for image maps.
@@ -476,6 +755,8 @@
    base_url = a_Url_dup(url);
    dw = NULL;
 
+   a_Bw_add_doc(p_bw, this);
+
    /* Init for-parsing variables */
    Start_Buf = NULL;
    Start_Ofs = 0;
@@ -584,6 +865,8 @@
 
    MSG("::~DilloHtml()\n");
 
+   a_Bw_remove_doc(bw, this);
+
    a_Url_free(base_url);
 
    for (i = 0; i < forms->size(); i++) {
@@ -759,7 +1042,8 @@
       } else {
          if (link == -1) {
             a_UIcmd_page_popup(bw, a_History_get_url(NAV_TOP_UIDX(bw)),
-                               bw->num_page_bugs ? bw->page_bugs->str:NULL);
+                               bw->num_page_bugs ? bw->page_bugs->str:NULL,
+                               prefs.load_images);
             ret = true;
          } else {
             a_UIcmd_link_popup(bw, html->links->get(link));
--- a/src/html.hh	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/html.hh	Wed Nov 14 22:27:26 2007 +0100
@@ -1,280 +1,21 @@
 #ifndef __HTML_HH__
 #define __HTML_HH__
 
-#include "d_size.h"            // for uchar_t
-#include "bw.h"                // for BrowserWindow
-
-#include "dw/core.hh"
-#include "lout/misc.hh"        // For SimpleVector
-
-//#include "dw_image.h"        // for DwImageMapList
-#include "image.hh"            // DilloImage for HtmlLinkImageReceiver
-
-#include "form.hh"             // For receiving the "clicked" signal
+#include "url.h"               // for DilloUrl
+#include "form.hh"             // for form::Form
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-typedef struct _DilloLinkImage   DilloLinkImage;
-
-typedef struct _DilloHtmlClass   DilloHtmlClass;
-typedef struct _DilloHtmlState   DilloHtmlState;
-typedef struct _DilloHtmlForm    DilloHtmlForm;
-typedef struct _DilloHtmlOption  DilloHtmlOption;
-typedef struct _DilloHtmlSelect  DilloHtmlSelect;
-typedef struct _DilloHtmlInput   DilloHtmlInput;
-
-
-struct _DilloLinkImage {
-   DilloUrl *url;
-   DilloImage *image;
-};
-
-
-typedef enum {
-   DT_NONE,           
-   DT_HTML,           
-   DT_XHTML
-} DilloHtmlDocumentType;
-
-typedef enum {
-   DILLO_HTML_PARSE_MODE_INIT = 0,
-   DILLO_HTML_PARSE_MODE_STASH,
-   DILLO_HTML_PARSE_MODE_STASH_AND_BODY,
-   DILLO_HTML_PARSE_MODE_VERBATIM,
-   DILLO_HTML_PARSE_MODE_BODY,
-   DILLO_HTML_PARSE_MODE_PRE
-} DilloHtmlParseMode;
-
-typedef enum {
-   SEEK_ATTR_START,
-   MATCH_ATTR_NAME,
-   SEEK_TOKEN_START,
-   SEEK_VALUE_START,
-   SKIP_VALUE,
-   GET_VALUE,
-   FINISHED
-} DilloHtmlTagParsingState;
-
-typedef enum {
-   HTML_LeftTrim      = 1 << 0,
-   HTML_RightTrim     = 1 << 1,
-   HTML_ParseEntities = 1 << 2
-} DilloHtmlTagParsingFlags;
-
-typedef enum {
-   DILLO_HTML_TABLE_MODE_NONE,  /* no table at all */
-   DILLO_HTML_TABLE_MODE_TOP,   /* outside of <tr> */
-   DILLO_HTML_TABLE_MODE_TR,    /* inside of <tr>, outside of <td> */
-   DILLO_HTML_TABLE_MODE_TD     /* inside of <td> */
-} DilloHtmlTableMode;
-
-typedef enum {
-   HTML_LIST_NONE,
-   HTML_LIST_UNORDERED,
-   HTML_LIST_ORDERED
-} DilloHtmlListMode;
-
-enum DilloHtmlProcessingState {
-   IN_NONE        = 0,
-   IN_HTML        = 1 << 0,
-   IN_HEAD        = 1 << 1,
-   IN_BODY        = 1 << 2,
-   IN_FORM        = 1 << 3,
-   IN_SELECT      = 1 << 4,
-   IN_TEXTAREA    = 1 << 5,
-   IN_MAP         = 1 << 6,
-   IN_PRE         = 1 << 7,
-   IN_BUTTON      = 1 << 8
-};
-
-
-struct _DilloHtmlState {
-   char *tag_name;
-   //DwStyle *style, *table_cell_style;
-   dw::core::style::Style *style, *table_cell_style;
-   DilloHtmlParseMode parse_mode;
-   DilloHtmlTableMode table_mode;
-   bool_t cell_text_align_set;
-   DilloHtmlListMode list_type;
-   int list_number;
-
-   /* TagInfo index for the tag that's being processed */
-   int tag_idx;
-
-   dw::core::Widget *textblock, *table;
-
-   /* This is used to align list items (especially in enumerated lists) */
-   dw::core::Widget *ref_list_item;
-
-   /* This makes image processing faster than a function
-      a_Dw_widget_get_background_color. */
-   int32_t current_bg_color;
-
-   /* This is used for list items etc; if it is set to TRUE, breaks
-      have to be "handed over" (see Html_add_indented and
-      Html_eventually_pop_dw). */
-   bool_t hand_over_break;
-};
-
-typedef enum {
-   DILLO_HTML_METHOD_UNKNOWN,
-   DILLO_HTML_METHOD_GET,
-   DILLO_HTML_METHOD_POST
-} DilloHtmlMethod;
-
-typedef enum {
-   DILLO_HTML_ENC_URLENCODING
-} DilloHtmlEnc;
-
-struct _DilloHtmlForm {
-   DilloHtmlMethod method;
-   DilloUrl *action;
-   DilloHtmlEnc enc;
-
-   misc::SimpleVector<DilloHtmlInput> *inputs;
-
-   int num_entry_fields;
-   int num_submit_buttons;
-
-   form::Form *form_receiver;
-};
-
-struct _DilloHtmlOption {
-   //GtkWidget *menuitem;
-   char *value;
-   bool_t init_val;
-};
-
-struct _DilloHtmlSelect {
-   //GtkWidget *menu;
-   int size;
-
-   DilloHtmlOption *options;
-   int num_options;
-   int num_options_max;
-};
-
-typedef enum {
-   DILLO_HTML_INPUT_UNKNOWN,
-   DILLO_HTML_INPUT_TEXT,
-   DILLO_HTML_INPUT_PASSWORD,
-   DILLO_HTML_INPUT_CHECKBOX,
-   DILLO_HTML_INPUT_RADIO,
-   DILLO_HTML_INPUT_IMAGE,
-   DILLO_HTML_INPUT_FILE,
-   DILLO_HTML_INPUT_BUTTON,
-   DILLO_HTML_INPUT_HIDDEN,
-   DILLO_HTML_INPUT_SUBMIT,
-   DILLO_HTML_INPUT_RESET,
-   DILLO_HTML_INPUT_BUTTON_SUBMIT,
-   DILLO_HTML_INPUT_BUTTON_RESET,
-   DILLO_HTML_INPUT_SELECT,
-   DILLO_HTML_INPUT_SEL_LIST,
-   DILLO_HTML_INPUT_TEXTAREA,
-   DILLO_HTML_INPUT_INDEX
-} DilloHtmlInputType;
-
-struct _DilloHtmlInput {
-   DilloHtmlInputType type;
-   void *widget;      /* May be a FLTKWidget or a Dw Widget. */
-   void *embed;       /* May be NULL */
-   char *name;
-   char *init_str;    /* note: some overloading - for buttons, init_str
-                         is simply the value of the button; for text
-                         entries, it is the initial value */
-   DilloHtmlSelect *select;
-   bool_t init_val;   /* only meaningful for buttons */
-};
-
-class DilloHtml {
-private:
-   class HtmlLinkReceiver: public dw::core::Widget::LinkReceiver {
-   public:
-      DilloHtml *html;
-
-      bool enter (dw::core::Widget *widget, int link, int img, int x, int y);
-      bool press (dw::core::Widget *widget, int link, int img, int x, int y,
-                  dw::core::EventButton *event);
-      bool click (dw::core::Widget *widget, int link, int img, int x, int y,
-                  dw::core::EventButton *event);
-   };
-   HtmlLinkReceiver linkReceiver;
-
-public:  //BUG: for now everything is public
-
-   BrowserWindow *bw;
-   DilloUrl *base_url;
-   dw::core::Widget *dw;    /* this is duplicated in the stack */
-
-   /* -------------------------------------------------------------------*/
-   /* Variables required at parsing time                                 */
-   /* -------------------------------------------------------------------*/
-   char *Start_Buf;
-   size_t Start_Ofs;
-   size_t CurrTagOfs;
-   size_t OldTagOfs, OldTagLine;
-
-   DilloHtmlDocumentType DocType; /* as given by DOCTYPE tag */
-   float DocTypeVersion;          /* HTML or XHTML version number */
-
-   misc::SimpleVector<DilloHtmlState> *stack;
-
-   int InFlags; /* tracks which elements we are in */
-
-   Dstr *Stash;
-   bool_t StashSpace;
-
-   char *SPCBuf;          /* Buffer for white space */
-
-   int pre_column;        /* current column, used in PRE tags with tabs */
-   bool_t PreFirstChar;   /* used to skip the first CR or CRLF in PRE tags */
-   bool_t PrevWasCR;      /* Flag to help parsing of "\r\n" in PRE tags */
-   bool_t PrevWasOpenTag; /* Flag to help deferred parsing of white space */
-   bool_t SPCPending;     /* Flag to help deferred parsing of white space */
-   bool_t InVisitedLink;  /* used to 'contrast_visited_colors' */
-   bool_t ReqTagClose;    /* Flag to help handling bad-formed HTML */
-   bool_t CloseOneTag;    /* Flag to help Html_tag_cleanup_at_close() */
-   bool_t TagSoup;        /* Flag to enable the parser's cleanup functions */
-   char *NameVal;         /* used for validation of "NAME" and "ID" in <A> */
-
-   /* element counters: used for validation purposes */
-   uchar_t Num_HTML, Num_HEAD, Num_BODY, Num_TITLE;
-
-   Dstr *attr_data;       /* Buffer for attribute value */
-
-   /* -------------------------------------------------------------------*/
-   /* Variables required after parsing (for page functionality)          */
-   /* -------------------------------------------------------------------*/
-   misc::SimpleVector<DilloHtmlForm> *forms;
-   misc::SimpleVector<DilloUrl*> *links;
-   misc::SimpleVector<DilloLinkImage*> *images;
-   //DwImageMapList maps;
-
-   int32_t link_color;
-   int32_t visited_color;
-
-private:
-   void initDw();  /* Used by the constructor */
-
-public:
-   DilloHtml(BrowserWindow *bw, const DilloUrl *url);
-   ~DilloHtml();
-   void connectSignals(dw::core::Widget *dw);
-   void write(char *Buf, int BufSize, int Eof);
-   void closeParser(int ClientKey);
-   int formNew(DilloHtmlMethod method, const DilloUrl *action,
-               DilloHtmlEnc enc);
-   void loadImages (const DilloUrl *pattern);
-};
-
 /*
  * Exported functions
  */
 void a_Html_form_event_handler(void *data,
                                form::Form *form_receiver,
                                void *v_resource);
+void a_Html_free(void *data);
+void a_Html_load_images(void *v_html, DilloUrl *pattern);
 
 #ifdef __cplusplus
 }
--- a/src/menu.cc	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/menu.cc	Wed Nov 14 22:27:26 2007 +0100
@@ -22,6 +22,7 @@
 #include "menu.hh"
 #include "uicmd.hh"
 #include "history.h"
+#include "html.hh"
 
 using namespace fltk;
 
@@ -149,6 +150,24 @@
    a_UIcmd_view_page_bugs(popup_bw);
 }
 
+/*
+ * Load images on current page that match URL pattern
+ *
+ * BUG: assumes that the document is a DilloHtml.
+ */
+static void Menu_load_images_cb(Widget*, void *user_data)
+{
+   DilloUrl *pattern = (DilloUrl *) user_data ;
+
+   if (popup_bw && popup_bw->Docs) {
+      int i, n;
+      n = dList_length(popup_bw->Docs);
+      for (i = 0; i < n; i++) {
+         a_Html_load_images(dList_nth_data(popup_bw->Docs, i), pattern);
+      }
+   }
+}
+
 /* 
  * Validate URL with the W3C
  */
@@ -205,16 +224,18 @@
  * Page popup menu (construction & popup)
  */
 void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url, 
-                       const char *bugs_txt)
+                       const char *bugs_txt, int prefs_load_images)
 {
    // One menu for every browser window
    static PopupMenu *pm = 0;
    // Active/inactive control.
    static Item *view_page_bugs_item = 0;
+   static Item *load_images_item = 0;
 
    popup_bw = bw;
    popup_url = url;
    popup_bugs = bugs_txt;
+
    if (!pm) {
       Item *i;
       pm = new PopupMenu(0,0,0,0,"&PAGE OPTIONS");
@@ -224,6 +245,8 @@
        //i->shortcut(CTRL+'n');
        i = view_page_bugs_item = new Item("View page Bugs");
        i->callback(Menu_view_page_bugs_cb);
+       i = load_images_item = new Item("Load images");
+       i->callback(Menu_load_images_cb);
        i = new Item("Bookmark this page");
        i->callback(Menu_add_bookmark_cb);
        new Divider();    
@@ -241,9 +264,17 @@
    }
 
    if (bugs_txt == NULL)
-       view_page_bugs_item->deactivate();
+      view_page_bugs_item->deactivate();
    else
-       view_page_bugs_item->activate();
+      view_page_bugs_item->activate();
+
+   if (prefs_load_images == 1)
+      load_images_item->deactivate();
+   else
+      load_images_item->activate();
+
+   // NULL is wildcard
+   load_images_item->user_data(NULL);
 
    // Make the popup a child of the calling UI object
    ((Group *)bw->ui)->add(pm);
@@ -295,7 +326,11 @@
 {
    // One menu for every browser window
    static PopupMenu *pm = 0;
-   Widget *link_menuitem;
+   // Active/inactive control.
+   static Item *link_menuitem = 0;
+   static Item *load_menuitem = 0;
+
+   DilloUrl *userdata_url = a_Url_dup(url);
 
    popup_bw = bw;
    popup_url = url;
@@ -304,27 +339,30 @@
       Item *i;
       pm = new PopupMenu(0,0,0,0,"&IMAGE OPTIONS");
       pm->begin();
-       i = new Item("Isolate Image");                     // 0
+       i = new Item("Isolate Image");
        i->callback(Menu_open_url_cb);
-       i = new Item("Open Image in New Window");          // 1
+       i = new Item("Open Image in New Window");
        i->callback(Menu_open_url_nw_cb);
-       i = new Item("Bookmark this Image");               // 2
+       i = load_menuitem = new Item("Load image");
+       i->callback(Menu_load_images_cb);
+       i = new Item("Bookmark this Image");
        i->callback(Menu_add_bookmark_cb);
-       i = new Item("Copy Image location");               // 3
+       i = new Item("Copy Image location");
        i->callback(Menu_unimplemented_cb);
        i->deactivate();
-       new Divider();                                     // 4
-       i = new Item("Save Image As...");                  // 5
+       new Divider();
+       i = new Item("Save Image As...");
        i->callback(Menu_save_link_cb);
-       new Divider();                                     // 6
-       i = new Item("Link menu");                         // 7
+       new Divider();
+       i = link_menuitem = new Item("Link menu");
        i->callback(Menu_link_cb);
 
       pm->type(PopupMenu::POPUP123);
       pm->end();
    }
 
-   link_menuitem = pm->child(7);                          // 7
+   // point to this item initially
+   pm->item(load_menuitem);
 
    if (link_url) {
       link_menuitem->user_data(link_url);
@@ -332,11 +370,15 @@
    } else {
       link_menuitem->deactivate();
    }
+
+   load_menuitem->user_data(userdata_url);
  
    // Make the popup a child of the calling UI object
    ((Group *)bw->ui)->add(pm);
 
    pm->popup();
+
+   a_Url_free(userdata_url);
 }
 
 /*
--- a/src/menu.hh	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/menu.hh	Wed Nov 14 22:27:26 2007 +0100
@@ -8,7 +8,7 @@
 #endif /* __cplusplus */
 
 void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url,
-                       const char *bugs_txt);
+                       const char *bugs_txt, int prefs_load_images);
 void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url);
 void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url,
                         DilloUrl *link_url);
--- a/src/plain.cc	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/plain.cc	Wed Nov 14 22:27:26 2007 +0100
@@ -142,7 +142,7 @@
    _MSG("DilloPlain::PlainEventReceiver::buttonPress\n");
 
    if (event->button == 3) {
-      a_UIcmd_page_popup(plain->bw, plain->url, NULL);
+      a_UIcmd_page_popup(plain->bw, plain->url, NULL, 1);
       return true;
    }
    return false;
--- a/src/uicmd.cc	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/uicmd.cc	Wed Nov 14 22:27:26 2007 +0100
@@ -443,9 +443,10 @@
 /*
  * Popup the page menu
  */
-void a_UIcmd_page_popup(void *vbw, const DilloUrl *url, const char *bugs_txt)
+void a_UIcmd_page_popup(void *vbw, const DilloUrl *url,
+                        const char *bugs_txt, int prefs_load_images)
 {
-   a_Menu_page_popup((BrowserWindow*)vbw, url, bugs_txt);
+   a_Menu_page_popup((BrowserWindow*)vbw, url, bugs_txt, prefs_load_images);
 }
 
 /*
--- a/src/uicmd.hh	Wed Nov 14 15:32:16 2007 +0100
+++ b/src/uicmd.hh	Wed Nov 14 22:27:26 2007 +0100
@@ -27,7 +27,8 @@
 void a_UIcmd_book(void *vbw);
 void a_UIcmd_add_bookmark(BrowserWindow *bw, const DilloUrl *url);
 void a_UIcmd_fullscreen_toggle(BrowserWindow *bw);
-void a_UIcmd_page_popup(void *vbw, const DilloUrl *url, const char *bugs_txt);
+void a_UIcmd_page_popup(void *vbw, const DilloUrl *url,
+                        const char *bugs_txt, int prefs_load_images);
 void a_UIcmd_link_popup(void *vbw, const DilloUrl *url);
 void a_UIcmd_image_popup(void *vbw, const DilloUrl *url, DilloUrl *link_url);
 void a_UIcmd_view_page_source(const DilloUrl *url);