summaryrefslogtreecommitdiff
path: root/frontends/windows
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-05-05 22:28:51 +0100
committerVincent Sanders <vince@kyllikki.org>2016-05-15 13:44:34 +0100
commitd21447d096a320a08b3efb2b8768fad0dcdcfd64 (patch)
tree1a83814b7c9e94b2f13c473261f23dd3a17dee64 /frontends/windows
parent2cbb337756d9af5bda4d594964d446439f602551 (diff)
downloadnetsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.gz
netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.bz2
move frontends into sub directory
Diffstat (limited to 'frontends/windows')
-rw-r--r--frontends/windows/Makefile75
-rw-r--r--frontends/windows/Makefile.defaults25
-rw-r--r--frontends/windows/about.c151
-rw-r--r--frontends/windows/about.h24
-rw-r--r--frontends/windows/bitmap.c387
-rw-r--r--frontends/windows/bitmap.h40
-rw-r--r--frontends/windows/download.c346
-rw-r--r--frontends/windows/download.h37
-rw-r--r--frontends/windows/drawable.c625
-rw-r--r--frontends/windows/drawable.h25
-rw-r--r--frontends/windows/file.c302
-rw-r--r--frontends/windows/file.h29
-rw-r--r--frontends/windows/filetype.c60
-rw-r--r--frontends/windows/filetype.h24
-rw-r--r--frontends/windows/findfile.c156
-rw-r--r--frontends/windows/findfile.h26
-rw-r--r--frontends/windows/font.c298
-rw-r--r--frontends/windows/font.h53
-rw-r--r--frontends/windows/gui.c170
-rw-r--r--frontends/windows/gui.h58
-rw-r--r--frontends/windows/localhistory.c401
-rw-r--r--frontends/windows/localhistory.h32
-rw-r--r--frontends/windows/main.c271
-rw-r--r--frontends/windows/plot.c868
-rw-r--r--frontends/windows/plot.h24
-rw-r--r--frontends/windows/pointers.c128
-rw-r--r--frontends/windows/pointers.h40
-rw-r--r--frontends/windows/prefs.c680
-rw-r--r--frontends/windows/prefs.h24
-rw-r--r--frontends/windows/res/NetSurf.icobin0 -> 18614 bytes
l---------frontends/windows/res/adblock.css1
-rw-r--r--frontends/windows/res/banner.bmpbin0 -> 79518 bytes
l---------frontends/windows/res/ca-bundle.crt1
l---------frontends/windows/res/credits.html1
l---------frontends/windows/res/default.css1
-rw-r--r--frontends/windows/res/home.bmpbin0 -> 2358 bytes
-rw-r--r--frontends/windows/res/icons/back.pngbin0 -> 653 bytes
-rw-r--r--frontends/windows/res/icons/back_g.pngbin0 -> 306 bytes
-rw-r--r--frontends/windows/res/icons/back_h.pngbin0 -> 607 bytes
-rw-r--r--frontends/windows/res/icons/forward.pngbin0 -> 697 bytes
-rw-r--r--frontends/windows/res/icons/forward_g.pngbin0 -> 538 bytes
-rw-r--r--frontends/windows/res/icons/forward_h.pngbin0 -> 635 bytes
-rw-r--r--frontends/windows/res/icons/home.pngbin0 -> 745 bytes
-rw-r--r--frontends/windows/res/icons/home_g.pngbin0 -> 576 bytes
-rw-r--r--frontends/windows/res/icons/home_h.pngbin0 -> 751 bytes
-rw-r--r--frontends/windows/res/icons/reload.pngbin0 -> 1062 bytes
-rw-r--r--frontends/windows/res/icons/reload_g.pngbin0 -> 814 bytes
-rw-r--r--frontends/windows/res/icons/reload_h.pngbin0 -> 1046 bytes
-rw-r--r--frontends/windows/res/icons/stop.pngbin0 -> 1135 bytes
-rw-r--r--frontends/windows/res/icons/stop_g.pngbin0 -> 850 bytes
-rw-r--r--frontends/windows/res/icons/stop_h.pngbin0 -> 1119 bytes
-rw-r--r--frontends/windows/res/installer.nsi141
l---------frontends/windows/res/internal.css1
l---------frontends/windows/res/licence.html1
-rw-r--r--frontends/windows/res/netsurf.gifbin0 -> 14119 bytes
l---------frontends/windows/res/netsurf.png1
l---------frontends/windows/res/quirks.css1
-rw-r--r--frontends/windows/res/resource.rc265
-rw-r--r--frontends/windows/res/throbber.avibin0 -> 23980 bytes
-rw-r--r--frontends/windows/res/throbber/throbber0.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber0.pngbin0 -> 730 bytes
-rw-r--r--frontends/windows/res/throbber/throbber1.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber1.pngbin0 -> 928 bytes
-rw-r--r--frontends/windows/res/throbber/throbber2.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber2.pngbin0 -> 906 bytes
-rw-r--r--frontends/windows/res/throbber/throbber3.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber3.pngbin0 -> 917 bytes
-rw-r--r--frontends/windows/res/throbber/throbber4.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber4.pngbin0 -> 927 bytes
-rw-r--r--frontends/windows/res/throbber/throbber5.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber5.pngbin0 -> 923 bytes
-rw-r--r--frontends/windows/res/throbber/throbber6.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber6.pngbin0 -> 904 bytes
-rw-r--r--frontends/windows/res/throbber/throbber7.bmpbin0 -> 1866 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber7.pngbin0 -> 940 bytes
-rwxr-xr-xfrontends/windows/res/throbber/throbber8.pngbin0 -> 921 bytes
-rw-r--r--frontends/windows/res/toolbar.bmpbin0 -> 8694 bytes
-rw-r--r--frontends/windows/res/toolbarg.bmpbin0 -> 8694 bytes
-rw-r--r--frontends/windows/res/toolbarh.bmpbin0 -> 8694 bytes
l---------frontends/windows/res/welcome.html1
-rw-r--r--frontends/windows/resourceid.h138
-rw-r--r--frontends/windows/schedule.c235
-rw-r--r--frontends/windows/schedule.h65
-rw-r--r--frontends/windows/windbg.c663
-rw-r--r--frontends/windows/windbg.h34
-rw-r--r--frontends/windows/window.c1741
-rw-r--r--frontends/windows/window.h109
87 files changed, 8779 insertions, 0 deletions
diff --git a/frontends/windows/Makefile b/frontends/windows/Makefile
new file mode 100644
index 000000000..a3a95d9da
--- /dev/null
+++ b/frontends/windows/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile for NetSurf Windows target
+#
+# This file is part of NetSurf
+
+LDFLAGS += -L${GCCSDK_INSTALL_ENV}/lib
+CFLAGS += -I${GCCSDK_INSTALL_ENV}/include/
+
+
+$(eval $(call pkg_config_find_and_add,libcares,Cares))
+$(eval $(call pkg_config_find_and_add,zlib,ZLib))
+
+
+LDFLAGS += -lssl -lcrypto -lgnurx -lgdi32 -lcomctl32 -lws2_32 -lmsimg32 -mwindows
+
+CFLAGS += -U__STRICT_ANSI__ -mwin32
+# only windows versions after XP are supported
+CFLAGS += '-DWINVER=0x0501'
+CFLAGS += '-D_WIN32_WINNT=0x0501'
+CFLAGS += '-D_WIN32_WINDOWS=0x0501'
+CFLAGS += '-D_WIN32_IE=0x0501'
+
+#installed resource path
+CFLAGS += '-DNETSURF_WINDOWS_RESPATH="$(NETSURF_WINDOWS_RESPATH)"'
+
+WSCFLAGS := -std=c99 -DCURL_STATICLIB -DCARES_STATICLIB -g
+
+CFLAGS += $(WSCFLAGS)
+LDFLAGS += $(WSCFLAGS)
+
+# ----------------------------------------------------------------------------
+# built-in resource setup
+# ----------------------------------------------------------------------------
+
+$(OBJROOT)/windows_resource.o: $(FRONTEND_RESOURCES_DIR)/resource.rc
+ $(VQ)echo " WINDRES: compiling windows resources"
+ ${Q}$(WINDRES) $< -O coff -o $@
+
+S_RESOURCES := windows_resource.o
+
+# ----------------------------------------------------------------------------
+# Source file setup
+# ----------------------------------------------------------------------------
+
+# sources purely for the windows build
+S_FRONTEND := main.c window.c gui.c drawable.c plot.c findfile.c \
+ font.c bitmap.c about.c prefs.c download.c filetype.c file.c \
+ localhistory.c schedule.c windbg.c pointers.c
+
+# This is the final source build list
+# Note this is deliberately *not* expanded here as common and image
+# are not yet available
+SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND) $(S_RESOURCES)
+EXETARGET := NetSurf.exe
+
+# ----------------------------------------------------------------------------
+# Install target
+# ----------------------------------------------------------------------------
+
+install-windows:
+
+# ----------------------------------------------------------------------------
+# Package target
+# ----------------------------------------------------------------------------
+
+package-windows: netsurf-installer.exe
+
+WIN_RES_OBJ := installer.nsi NetSurf.ico netsurf.png welcome.html default.css
+WIN_RES_INS_OBJ := $(addprefix $(FRONTEND_RESOURCES_DIR)/,$(WIN_RES_OBJ)) $(OBJROOT)/messages
+
+$(OBJROOT)/messages: resources/FatMessages
+ $(Q)$(SPLIT_MESSAGES) -l en -p win -f messages resources/FatMessages > $@
+
+netsurf-installer.exe: $(EXETARGET) $(WIN_RES_INS_OBJ)
+ makensis -V4 -NOCD $(FRONTEND_RESOURCES_DIR)/installer.nsi
diff --git a/frontends/windows/Makefile.defaults b/frontends/windows/Makefile.defaults
new file mode 100644
index 000000000..1d844f112
--- /dev/null
+++ b/frontends/windows/Makefile.defaults
@@ -0,0 +1,25 @@
+# ----------------------------------------------------------------------------
+# windows-specific options
+# ----------------------------------------------------------------------------
+
+# Where to search for NetSurf's resources after looking in ~/.netsurf and
+# $NETSURFRES. It must have a trailing backslash
+NETSURF_WINDOWS_RESPATH :=
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO
+NETSURF_USE_NSSVG := NO
+
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
+
+# no pdf support
+NETSURF_USE_HARU_PDF := NO
+
+# Optimisation levels
+CFLAGS += -O2
diff --git a/frontends/windows/about.c b/frontends/windows/about.c
new file mode 100644
index 000000000..4716a5c91
--- /dev/null
+++ b/frontends/windows/about.c
@@ -0,0 +1,151 @@
+/*
+* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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
+ * This is The win32 API about dialog implementation.
+ */
+
+#include <stdio.h>
+
+#include "utils/config.h"
+
+#include <windows.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/messages.h"
+#include "desktop/version.h"
+
+#include "windows/gui.h"
+#include "windows/window.h"
+#include "windows/about.h"
+#include "windows/resourceid.h"
+
+#include "windbg.h"
+
+/**
+ * Initialize the about dialog text fields
+ */
+static BOOL init_about_dialog(HWND hwnd)
+{
+ char ver_str[128];
+ HWND dlg_itm;
+ HFONT hFont;
+
+ dlg_itm = GetDlgItem(hwnd, IDC_ABOUT_VERSION);
+ if (dlg_itm != NULL) {
+
+ hFont=CreateFont (26, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
+ if (hFont != NULL) {
+ LOG("Setting font object");
+ SendMessage(dlg_itm, WM_SETFONT, (WPARAM)hFont, 0);
+ }
+
+ snprintf(ver_str, sizeof(ver_str), "%s %s",
+ messages_get("NetSurf"), netsurf_version);
+
+ SendMessage(dlg_itm, WM_SETTEXT, 0, (LPARAM)ver_str);
+ }
+
+ dlg_itm = GetDlgItem(hwnd, IDC_ABOUT_COPYRIGHT);
+ if (dlg_itm != NULL) {
+ snprintf(ver_str, sizeof(ver_str), "%s",
+ messages_get("NetSurfCopyright"));
+
+ SendMessage(dlg_itm, WM_SETTEXT, 0, (LPARAM)ver_str);
+ }
+
+ return TRUE;
+}
+
+/**
+ * destroy resources used to create about dialog
+ */
+static BOOL destroy_about_dialog(HWND hwnd)
+{
+ HWND dlg_itm;
+ HFONT hFont;
+
+ dlg_itm = GetDlgItem(hwnd, IDC_ABOUT_VERSION);
+ if (dlg_itm != NULL) {
+ hFont = (HFONT)SendMessage(dlg_itm, WM_GETFONT, 0, 0);
+ if (hFont != NULL) {
+ LOG("Destroyed font object");
+ DeleteObject(hFont);
+ }
+ }
+
+ return TRUE;
+
+}
+
+static BOOL CALLBACK
+nsws_about_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ return init_about_dialog(hwnd);
+
+ case WM_COMMAND:
+ switch(LOWORD(wparam)) {
+ case IDOK:
+ LOG("OK clicked");
+ EndDialog(hwnd, IDOK);
+ break;
+
+ case IDCANCEL:
+ LOG("Cancel clicked");
+ EndDialog(hwnd, IDOK);
+ break;
+
+ case IDC_BTN_CREDITS:
+ nsws_window_go(hwnd, "about:credits");
+ EndDialog(hwnd, IDOK);
+ break;
+
+ case IDC_BTN_LICENCE:
+ nsws_window_go(hwnd, "about:licence");
+ EndDialog(hwnd, IDOK);
+ break;
+
+ }
+ break;
+
+ case WM_CREATE:
+ return TRUE;
+
+ case WM_DESTROY:
+ return destroy_about_dialog(hwnd);
+
+ }
+ return FALSE;
+}
+
+void nsws_about_dialog_init(HINSTANCE hinst, HWND parent)
+{
+ int ret = DialogBox(hinst, MAKEINTRESOURCE(IDD_DLG_ABOUT), parent,
+ nsws_about_event_callback);
+ if (ret == -1) {
+ win32_warning(messages_get("NoMemory"), 0);
+ return;
+ }
+}
diff --git a/frontends/windows/about.h b/frontends/windows/about.h
new file mode 100644
index 000000000..e0315b507
--- /dev/null
+++ b/frontends/windows/about.h
@@ -0,0 +1,24 @@
+/*
+* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+*/
+
+#ifndef _NETSURF_WINDOWS_ABOUT_H_
+#define _NETSURF_WINDOWS_ABOUT_H_
+
+void nsws_about_dialog_init(HINSTANCE hinst, HWND parent);
+
+#endif
diff --git a/frontends/windows/bitmap.c b/frontends/windows/bitmap.c
new file mode 100644
index 000000000..664244838
--- /dev/null
+++ b/frontends/windows/bitmap.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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
+ * win32 implementation of the bitmap operations.
+ */
+
+#include "utils/config.h"
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <string.h>
+#include <windows.h>
+
+#include "utils/log.h"
+#include "image/bitmap.h"
+#include "desktop/plotters.h"
+#include "content/content.h"
+
+#include "windows/plot.h"
+#include "windows/bitmap.h"
+
+/**
+ * Create a bitmap.
+ *
+ * \param width width of image in pixels
+ * \param height width of image in pixels
+ * \param state a flag word indicating the initial state
+ * \return an opaque struct bitmap, or NULL on memory exhaustion
+ */
+void *win32_bitmap_create(int width, int height, unsigned int state)
+{
+ struct bitmap *bitmap;
+ BITMAPV5HEADER *pbmi;
+ HBITMAP windib;
+ uint8_t *pixdata;
+
+ LOG("width %d, height %d, state %u", width, height, state);
+
+ pbmi = calloc(1, sizeof(BITMAPV5HEADER));
+ if (pbmi == NULL) {
+ return NULL;
+ }
+
+ pbmi->bV5Size = sizeof(BITMAPV5HEADER);
+ pbmi->bV5Width = width;
+ pbmi->bV5Height = -height;
+ pbmi->bV5Planes = 1;
+ pbmi->bV5BitCount = 32;
+ pbmi->bV5Compression = BI_BITFIELDS;
+
+ pbmi->bV5RedMask = 0xff; /* red mask */
+ pbmi->bV5GreenMask = 0xff00; /* green mask */
+ pbmi->bV5BlueMask = 0xff0000; /* blue mask */
+ pbmi->bV5AlphaMask = 0xff000000; /* alpha mask */
+
+ windib = CreateDIBSection(NULL, (BITMAPINFO *)pbmi, DIB_RGB_COLORS, (void **)&pixdata, NULL, 0);
+
+ if (windib == NULL) {
+ free(pbmi);
+ return NULL;
+ }
+
+ bitmap = calloc(1 , sizeof(struct bitmap));
+ if (bitmap == NULL) {
+ DeleteObject(windib);
+ free(pbmi);
+ return NULL;
+ }
+
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->windib = windib;
+ bitmap->pbmi = pbmi;
+ bitmap->pixdata = pixdata;
+ if ((state & BITMAP_OPAQUE) != 0) {
+ bitmap->opaque = true;
+ } else {
+ bitmap->opaque = false;
+ }
+
+ LOG("bitmap %p", bitmap);
+
+ return bitmap;
+}
+
+
+/**
+ * Return a pointer to the pixel data in a bitmap.
+ *
+ * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
+ * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ * \return pointer to the pixel buffer
+ */
+static unsigned char *bitmap_get_buffer(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return NULL;
+ }
+
+ return bm->pixdata;
+}
+
+
+/**
+ * Find the width of a pixel row in bytes.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ * \return width of a pixel row in the bitmap
+ */
+static size_t bitmap_get_rowstride(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return 0;
+ }
+
+ return (bm->width) * 4;
+}
+
+
+/**
+ * Free a bitmap.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+void win32_bitmap_destroy(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return;
+ }
+
+ DeleteObject(bm->windib);
+ free(bm->pbmi);
+ free(bm);
+}
+
+
+/**
+ * Save a bitmap in the platform's native format.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ * \param path pathname for file
+ * \param flags flags controlling how the bitmap is saved.
+ * \return true on success, false on error and error reported
+ */
+static bool bitmap_save(void *bitmap, const char *path, unsigned flags)
+{
+ return true;
+}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+static void bitmap_modified(void *bitmap) {
+}
+
+/**
+ * Sets whether a bitmap should be plotted opaque
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ * \param opaque whether the bitmap should be plotted opaque
+ */
+static void bitmap_set_opaque(void *bitmap, bool opaque)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return;
+ }
+
+ LOG("setting bitmap %p to %s", bm, opaque ? "opaque" : "transparent");
+ bm->opaque = opaque;
+}
+
+
+/**
+ * Tests whether a bitmap has an opaque alpha channel
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ * \return whether the bitmap is opaque
+ */
+static bool bitmap_test_opaque(void *bitmap)
+{
+ int tst;
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return false;
+ }
+
+ tst = bm->width * bm->height;
+
+ while (tst-- > 0) {
+ if (bm->pixdata[(tst << 2) + 3] != 0xff) {
+ LOG("bitmap %p has transparency", bm);
+ return false;
+ }
+ }
+ LOG("bitmap %p is opaque", bm);
+ return true;
+}
+
+
+/**
+ * Gets whether a bitmap should be plotted opaque
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+static bool bitmap_get_opaque(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return false;
+ }
+
+ return bm->opaque;
+}
+
+static int bitmap_get_width(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return 0;
+ }
+
+ return(bm->width);
+}
+
+static int bitmap_get_height(void *bitmap)
+{
+ struct bitmap *bm = bitmap;
+
+ if (bitmap == NULL) {
+ LOG("NULL bitmap!");
+ return 0;
+ }
+
+ return(bm->height);
+}
+
+static size_t bitmap_get_bpp(void *bitmap)
+{
+ return 4;
+}
+
+struct bitmap *bitmap_scale(struct bitmap *prescale, int width, int height)
+{
+ struct bitmap *ret = malloc(sizeof(struct bitmap));
+ int i, ii, v, vv;
+ uint32_t *retpixdata, *inpixdata; /* 4 byte types for quicker
+ * transfer */
+ if (ret == NULL)
+ return NULL;
+
+ retpixdata = malloc(width * height * 4);
+ if (retpixdata == NULL) {
+ free(ret);
+ return NULL;
+ }
+
+ inpixdata = (uint32_t *)prescale->pixdata;
+ ret->pixdata = (uint8_t *)retpixdata;
+ ret->height = height;
+ ret->width = width;
+ for (i = 0; i < height; i++) {
+ v = i * width;
+ vv = (int)((i * prescale->height) / height) * prescale->width;
+ for (ii = 0; ii < width; ii++) {
+ retpixdata[v + ii] = inpixdata[vv + (int)
+ ((ii * prescale->width) / width)];
+ }
+ }
+ return ret;
+
+}
+
+
+static nserror
+bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
+{
+ int width;
+ int height;
+ HDC hdc, bufferdc, minidc;
+ struct bitmap *fsbitmap;
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = true,
+ .plot = &win_plotters
+ };
+
+ width = min(content_get_width(content), 1024);
+ height = ((width * bitmap->height) + (bitmap->width / 2)) /
+ bitmap->width;
+
+ LOG("bitmap %p for content %p width %d, height %d",
+ bitmap, content, width, height);
+
+ /* create two memory device contexts to put the bitmaps in */
+ bufferdc = CreateCompatibleDC(NULL);
+ if ((bufferdc == NULL)) {
+ return NSERROR_NOMEM;
+ }
+
+ minidc = CreateCompatibleDC(NULL);
+ if ((minidc == NULL)) {
+ DeleteDC(bufferdc);
+ return NSERROR_NOMEM;
+ }
+
+ /* create a full size bitmap and plot into it */
+ fsbitmap = win32_bitmap_create(width, height, BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE);
+
+ SelectObject(bufferdc, fsbitmap->windib);
+
+ hdc = plot_hdc;
+ plot_hdc = bufferdc;
+ /* render the content */
+ content_scaled_redraw(content, width, height, &ctx);
+ plot_hdc = hdc;
+
+ /* scale bitmap bufferbm into minibm */
+ SelectObject(minidc, bitmap->windib);
+
+ bitmap->opaque = true;
+
+ StretchBlt(minidc, 0, 0, bitmap->width, bitmap->height, bufferdc, 0, 0, width, height, SRCCOPY);
+
+ DeleteDC(bufferdc);
+ DeleteDC(minidc);
+ win32_bitmap_destroy(fsbitmap);
+
+ return NSERROR_OK;
+}
+
+static struct gui_bitmap_table bitmap_table = {
+ .create = win32_bitmap_create,
+ .destroy = win32_bitmap_destroy,
+ .set_opaque = bitmap_set_opaque,
+ .get_opaque = bitmap_get_opaque,
+ .test_opaque = bitmap_test_opaque,
+ .get_buffer = bitmap_get_buffer,
+ .get_rowstride = bitmap_get_rowstride,
+ .get_width = bitmap_get_width,
+ .get_height = bitmap_get_height,
+ .get_bpp = bitmap_get_bpp,
+ .save = bitmap_save,
+ .modified = bitmap_modified,
+ .render = bitmap_render,
+};
+
+struct gui_bitmap_table *win32_bitmap_table = &bitmap_table;
diff --git a/frontends/windows/bitmap.h b/frontends/windows/bitmap.h
new file mode 100644
index 000000000..c723159e1
--- /dev/null
+++ b/frontends/windows/bitmap.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_BITMAP_H_
+#define _NETSURF_WINDOWS_BITMAP_H_
+
+struct gui_bitmap_table *win32_bitmap_table;
+
+struct bitmap {
+ HBITMAP windib;
+ BITMAPV5HEADER *pbmi;
+ int width;
+ int height;
+ uint8_t *pixdata;
+ bool opaque;
+};
+
+struct bitmap *bitmap_scale(struct bitmap *prescale, int width, int height);
+
+void *win32_bitmap_create(int width, int height, unsigned int state);
+
+void win32_bitmap_destroy(void *bitmap);
+
+#endif
diff --git a/frontends/windows/download.c b/frontends/windows/download.c
new file mode 100644
index 000000000..b281ea76a
--- /dev/null
+++ b/frontends/windows/download.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include <limits.h>
+
+#include "utils/config.h"
+
+#include <shlobj.h>
+#include <windows.h>
+
+#include "utils/sys_time.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+#include "utils/string.h"
+#include "content/fetch.h"
+#include "desktop/gui_download.h"
+#include "desktop/download.h"
+
+#include "windows/download.h"
+#include "windows/window.h"
+#include "windows/gui.h"
+#include "windows/resourceid.h"
+#include "windows/schedule.h"
+
+struct gui_download_window {
+ HWND hwnd;
+ char *title;
+ char *filename;
+ char *domain;
+ char *time_left;
+ char *total_size;
+ char *original_total_size;
+ int size;
+ int downloaded;
+ unsigned int progress;
+ int time_remaining;
+ struct timeval start_time;
+ int speed;
+ int error;
+ struct gui_window *window;
+ FILE *file;
+ download_status status;
+};
+
+static bool downloading = false;
+static struct gui_download_window *download1;
+
+BOOL CALLBACK nsws_download_event_callback(HWND hwnd, UINT msg, WPARAM wparam,
+ LPARAM lparam);
+static void nsws_download_update_label(void *p);
+static void nsws_download_update_progress(void *p);
+static void nsws_download_clear_data(struct gui_download_window *w);
+
+static bool nsws_download_window_up(struct gui_download_window *w)
+{
+ w->hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DLG_DOWNLOAD),
+ gui_window_main_window(w->window),
+ nsws_download_event_callback);
+ if (w->hwnd == NULL) {
+ return false;
+ }
+ ShowWindow(w->hwnd, SW_SHOW);
+ return true;
+}
+
+static struct gui_download_window *
+gui_download_window_create(download_context *ctx, struct gui_window *gui)
+{
+ if (downloading) {
+ /* initial implementation */
+ win32_warning("1 download at a time please", 0);
+ return NULL;
+ }
+ downloading = true;
+ struct gui_download_window *w =
+ malloc(sizeof(struct gui_download_window));
+ if (w == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ int total_size = download_context_get_total_length(ctx);
+ char *domain, *filename, *destination;
+ nsurl *url = download_context_get_url(ctx);
+ bool unknown_size = (total_size == 0);
+ const char *size = (unknown_size) ?
+ messages_get("UnknownSize") :
+ human_friendly_bytesize(total_size);
+
+ if (nsurl_nice(url, &filename, false) != NSERROR_OK) {
+ filename = strdup(messages_get("UnknownFile"));
+ }
+ if (filename == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(w);
+ return NULL;
+ }
+
+ if (nsurl_has_component(url, NSURL_HOST)) {
+ domain = strdup(lwc_string_data(nsurl_get_component(url, NSURL_HOST)));
+ } else {
+ domain = strdup(messages_get("UnknownHost"));
+ }
+ if (domain == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ destination = malloc(PATH_MAX);
+ if (destination == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(domain);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT,
+ destination);
+ if (strlen(destination) < PATH_MAX - 2)
+ strcat(destination, "/");
+ if (strlen(destination) + strlen(filename) < PATH_MAX - 1)
+ strcat(destination, filename);
+ LOG("download %s [%s] from %s to %s", filename, size, domain, destination);
+ w->title = filename;
+ w->domain = domain;
+ w->size = total_size;
+ w->total_size = strdup(size);
+ if (w->total_size == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ w->downloaded = 0;
+ w->speed = 0;
+ gettimeofday(&(w->start_time), NULL);
+ w->time_remaining = -1;
+ w->time_left = NULL;
+ w->status = DOWNLOAD_NONE;
+ w->filename = destination;
+ w->progress = 0;
+ w->error = 0;
+ w->window = gui;
+ w->file = fopen(destination, "wb");
+ if (w->file == NULL) {
+ win32_warning(messages_get("FileOpenWriteError"), destination);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w->total_size);
+ free(w->time_left);
+ free(w);
+ return NULL;
+ }
+ download1 = w;
+
+ if (nsws_download_window_up(w) == false) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w->total_size);
+ free(w->time_left);
+ free(w);
+ return NULL;
+ }
+ return w;
+}
+
+
+BOOL CALLBACK nsws_download_event_callback(HWND hwnd, UINT msg, WPARAM wparam,
+ LPARAM lparam)
+{
+ HWND sub;
+ switch(msg){
+ case WM_INITDIALOG:
+ sub = GetDlgItem(hwnd, IDC_DOWNLOAD_LABEL);
+ nsws_download_update_label((void *)download1);
+ nsws_download_update_progress((void *)download1);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wparam)) {
+ case IDOK:
+ if (download1->downloaded != download1->size)
+ return TRUE;
+ case IDCANCEL:
+ nsws_download_clear_data(download1);
+ download1 = NULL;
+ downloading = false;
+ EndDialog(hwnd, IDCANCEL);
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+void nsws_download_update_label(void *p)
+{
+ struct gui_download_window *w = p;
+ if (w->hwnd == NULL) {
+ win32_schedule(-1, nsws_download_update_label, p);
+ return;
+ }
+ HWND sub = GetDlgItem(w->hwnd, IDC_DOWNLOAD_LABEL);
+ char *size = human_friendly_bytesize(w->downloaded);
+ int i = 0, temp = w->time_remaining;
+ if (temp == -1) {
+ w->time_left = strdup(messages_get("UnknownSize"));
+ i = strlen(w->time_left);
+ } else {
+ do {
+ temp = temp / 10;
+ i++;
+ } while (temp > 2);
+ w->time_left = malloc(i + SLEN(" s") + 1);
+ if (w->time_left != NULL) {
+ if (w->time_remaining > 3600)
+ sprintf(w->time_left, "%d h",
+ w->time_remaining / 3600);
+ else if (w->time_remaining > 60)
+ sprintf(w->time_left, "%d m",
+ w->time_remaining / 60);
+ else
+ sprintf(w->time_left, "%d s",
+ w->time_remaining);
+ }
+ }
+ char label[strlen(w->title) + strlen(size) + strlen(w->total_size) +
+ + strlen(w->domain) + strlen(w->filename) +
+ SLEN("download from to \n[\t/\t]\n estimate of time"
+ " remaining ") + i + 1];
+ sprintf(label, "download %s from %s to %s\n[%s\t/\t%s] [%d%%]\n"
+ "estimate of time remaining %s", w->title, w->domain,
+ w->filename, size, w->total_size, w->progress / 100,
+ w->time_left);
+ if (w->time_left != NULL) {
+ free(w->time_left);
+ w->time_left = NULL;
+ }
+ SendMessage(sub, WM_SETTEXT, (WPARAM)0, (LPARAM)label);
+ if (w->progress < 10000) {
+ win32_schedule(500, nsws_download_update_label, p);
+ }
+}
+
+void nsws_download_update_progress(void *p)
+{
+ struct gui_download_window *w = p;
+ if (w->hwnd == NULL) {
+ win32_schedule(-1, nsws_download_update_progress, p);
+ return;
+ }
+ HWND sub = GetDlgItem(w->hwnd, IDC_DOWNLOAD_PROGRESS);
+ SendMessage(sub, PBM_SETPOS, (WPARAM)(w->progress / 100), 0);
+ if (w->progress < 10000) {
+ win32_schedule(500, nsws_download_update_progress, p);
+ }
+}
+
+void nsws_download_clear_data(struct gui_download_window *w)
+{
+ if (w == NULL)
+ return;
+ if (w->title != NULL)
+ free(w->title);
+ if (w->filename != NULL)
+ free(w->filename);
+ if (w->domain != NULL)
+ free(w->domain);
+ if (w->time_left != NULL)
+ free(w->time_left);
+ if (w->total_size != NULL)
+ free(w->total_size);
+ if (w->file != NULL)
+ fclose(w->file);
+ win32_schedule(-1, nsws_download_update_progress, (void *)w);
+ win32_schedule(-1, nsws_download_update_label, (void *)w);
+}
+
+
+static nserror
+gui_download_window_data(struct gui_download_window *w, const char *data,
+ unsigned int size)
+{
+ if ((w == NULL) || (w->file == NULL))
+ return NSERROR_SAVE_FAILED;
+ size_t res;
+ struct timeval val;
+ res = fwrite((void *)data, 1, size, w->file);
+ if (res != size)
+ LOG("file write error %d of %d", size - res, size);
+ w->downloaded += res;
+ w->progress = (unsigned int)(((long long)(w->downloaded) * 10000)
+ / w->size);
+ gettimeofday(&val, NULL);
+ w->time_remaining = (w->progress == 0) ? -1 :
+ (int)((val.tv_sec - w->start_time.tv_sec) *
+ (10000 - w->progress) / w->progress);
+ return NSERROR_OK;
+}
+
+static void gui_download_window_error(struct gui_download_window *w,
+ const char *error_msg)
+{
+ LOG("error %s", error_msg);
+}
+
+static void gui_download_window_done(struct gui_download_window *w)
+{
+ if (w == NULL)
+ return;
+ downloading = false;
+ if (w->hwnd != NULL)
+ EndDialog(w->hwnd, IDOK);
+ nsws_download_clear_data(w);
+}
+
+static struct gui_download_table download_table = {
+ .create = gui_download_window_create,
+ .data = gui_download_window_data,
+ .error = gui_download_window_error,
+ .done = gui_download_window_done,
+};
+
+struct gui_download_table *win32_download_table = &download_table;
+
diff --git a/frontends/windows/download.h b/frontends/windows/download.h
new file mode 100644
index 000000000..2fe3b54c9
--- /dev/null
+++ b/frontends/windows/download.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_DOWNLOAD_H_
+#define _NETSURF_WINDOWS_DOWNLOAD_H_
+
+extern struct gui_download_table *win32_download_table;
+
+typedef enum {
+ DOWNLOAD_NONE,
+ DOWNLOAD_WORKING,
+ DOWNLOAD_ERROR,
+ DOWNLOAD_COMPLETE,
+ DOWNLOAD_CANCELED
+} download_status;
+
+/**
+ * Initialise the win32 window class for the download window
+ */
+void nsws_download_window_init(struct gui_window *);
+
+#endif
diff --git a/frontends/windows/drawable.c b/frontends/windows/drawable.c
new file mode 100644
index 000000000..4480eeaaa
--- /dev/null
+++ b/frontends/windows/drawable.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#include <stdbool.h>
+
+#include "utils/config.h"
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include "desktop/browser.h"
+#include "desktop/textinput.h"
+#include "desktop/plotters.h"
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+
+#include "windows/windbg.h"
+#include "windows/plot.h"
+#include "windows/window.h"
+#include "windows/localhistory.h"
+#include "windows/drawable.h"
+
+static const char windowclassname_drawable[] = "nswsdrawablewindow";
+
+/**
+ * Handle wheel scroll messages.
+ */
+static LRESULT
+nsws_drawable_wheel(struct gui_window *gw, HWND hwnd, WPARAM wparam)
+{
+ int i, z = GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
+ int key = LOWORD(wparam);
+ DWORD command;
+ unsigned int newmessage = WM_VSCROLL;
+
+ if (key == MK_SHIFT) {
+ command = (z > 0) ? SB_LINERIGHT : SB_LINELEFT;
+ newmessage = WM_HSCROLL;
+ } else {
+ /* add MK_CONTROL -> zoom */
+ command = (z > 0) ? SB_LINEUP : SB_LINEDOWN;
+ }
+
+ z = (z < 0) ? -1 * z : z;
+
+ for (i = 0; i < z; i++) {
+ SendMessage(hwnd, newmessage, MAKELONG(command, 0), 0);
+ }
+
+ return 0;
+}
+
+/**
+ * Handle vertical scroll messages.
+ */
+static LRESULT
+nsws_drawable_vscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
+{
+ int width, height;
+ SCROLLINFO si;
+ int mem;
+
+ LOG("VSCROLL %d", gw->requestscrolly);
+
+ if (gw->requestscrolly != 0)
+ return 0;
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ mem = si.nPos;
+
+ switch (LOWORD(wparam)) {
+ case SB_TOP:
+ si.nPos = si.nMin;
+ break;
+
+ case SB_BOTTOM:
+ si.nPos = si.nMax;
+ break;
+
+ case SB_LINEUP:
+ si.nPos -= 30;
+ break;
+
+ case SB_LINEDOWN:
+ si.nPos += 30;
+ break;
+
+ case SB_PAGEUP:
+ si.nPos -= gw->height;
+ break;
+
+ case SB_PAGEDOWN:
+ si.nPos += gw->height;
+ break;
+
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+
+ default:
+ break;
+ }
+
+ si.fMask = SIF_POS;
+ if ((gw->bw != NULL) &&
+ (browser_window_get_extents(gw->bw, true,
+ &width, &height) == NSERROR_OK)) {
+ si.nPos = min(si.nPos, height - gw->height);
+ }
+
+ si.nPos = max(si.nPos, 0);
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ if (si.nPos != mem) {
+ win32_window_set_scroll(gw, gw->scrollx, gw->scrolly +
+ gw->requestscrolly + si.nPos - mem);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Handle horizontal scroll messages.
+ */
+static LRESULT
+nsws_drawable_hscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
+{
+ int width, height;
+ SCROLLINFO si;
+ int mem;
+
+ LOG("HSCROLL %d", gw->requestscrollx);
+
+ if (gw->requestscrollx != 0)
+ return 0;
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ mem = si.nPos;
+
+ switch (LOWORD(wparam)) {
+ case SB_LINELEFT:
+ si.nPos -= 30;
+ break;
+
+ case SB_LINERIGHT:
+ si.nPos += 30;
+ break;
+
+ case SB_PAGELEFT:
+ si.nPos -= gw->width;
+ break;
+
+ case SB_PAGERIGHT:
+ si.nPos += gw->width;
+ break;
+
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+
+ default:
+ break;
+ }
+
+ si.fMask = SIF_POS;
+
+ if ((gw->bw != NULL) &&
+ (browser_window_get_extents(gw->bw, true,
+ &width, &height) == NSERROR_OK)) {
+ si.nPos = min(si.nPos, width - gw->width);
+ }
+ si.nPos = max(si.nPos, 0);
+ SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ if (si.nPos != mem) {
+ win32_window_set_scroll(gw,
+ gw->scrollx + gw->requestscrollx + si.nPos - mem,
+ gw->scrolly);
+ }
+
+ return 0;
+}
+
+/**
+ * Handle resize events.
+ */
+static LRESULT
+nsws_drawable_resize(struct gui_window *gw)
+{
+ browser_window_schedule_reformat(gw->bw);
+ return 0;
+}
+
+/**
+ * Handle key press messages.
+ */
+static LRESULT
+nsws_drawable_key(struct gui_window *gw, HWND hwnd, WPARAM wparam)
+{
+ if (GetFocus() != hwnd)
+ return 0 ;
+
+ uint32_t i;
+ bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);
+ bool capslock = ((GetKeyState(VK_CAPITAL) & 1) == 1);
+
+ switch(wparam) {
+ case VK_LEFT:
+ i = NS_KEY_LEFT;
+ if (shift)
+ SendMessage(hwnd, WM_HSCROLL,
+ MAKELONG(SB_LINELEFT, 0), 0);
+ break;
+
+ case VK_RIGHT:
+ i = NS_KEY_RIGHT;
+ if (shift)
+ SendMessage(hwnd, WM_HSCROLL,
+ MAKELONG(SB_LINERIGHT, 0), 0);
+ break;
+
+ case VK_UP:
+ i = NS_KEY_UP;
+ if (shift)
+ SendMessage(hwnd, WM_VSCROLL,
+ MAKELONG(SB_LINEUP, 0), 0);
+ break;
+
+ case VK_DOWN:
+ i = NS_KEY_DOWN;
+ if (shift)
+ SendMessage(hwnd, WM_VSCROLL,
+ MAKELONG(SB_LINEDOWN, 0), 0);
+ break;
+
+ case VK_HOME:
+ i = NS_KEY_LINE_START;
+ if (shift)
+ SendMessage(hwnd, WM_HSCROLL,
+ MAKELONG(SB_PAGELEFT, 0), 0);
+ break;
+
+ case VK_END:
+ i = NS_KEY_LINE_END;
+ if (shift)
+ SendMessage(hwnd, WM_HSCROLL,
+ MAKELONG(SB_PAGERIGHT, 0), 0);
+ break;
+
+ case VK_DELETE:
+ i = NS_KEY_DELETE_RIGHT;
+ break;
+
+ case VK_NEXT:
+ i = wparam;
+ SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0),
+ 0);
+ break;
+
+ case VK_PRIOR:
+ i = wparam;
+ SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0),
+ 0);
+ break;
+
+ default:
+ i = wparam;
+ break;
+ }
+
+ if ((i >= 'A') &&
+ (i <= 'Z') &&
+ (((!capslock) && (!shift)) || ((capslock) && (shift)))) {
+ i += 'a' - 'A';
+ }
+
+ if (gw != NULL)
+ browser_window_key_press(gw->bw, i);
+
+ return 0;
+}
+
+
+/**
+ * Handle paint messages.
+ */
+static LRESULT
+nsws_drawable_paint(struct gui_window *gw, HWND hwnd)
+{
+ struct rect clip;
+ PAINTSTRUCT ps;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &win_plotters
+ };
+
+ BeginPaint(hwnd, &ps);
+
+ if (gw != NULL) {
+ plot_hdc = ps.hdc;
+
+ clip.x0 = ps.rcPaint.left;
+ clip.y0 = ps.rcPaint.top;
+ clip.x1 = ps.rcPaint.right;
+ clip.y1 = ps.rcPaint.bottom;
+
+ browser_window_redraw(gw->bw,
+ -gw->scrollx / gw->scale,
+ -gw->scrolly / gw->scale,
+ &clip, &ctx);
+ }
+
+ EndPaint(hwnd, &ps);
+
+ return 0;
+}
+
+
+/**
+ * Handle mouse button up messages.
+ */
+static LRESULT
+nsws_drawable_mouseup(struct gui_window *gw,
+ int x,
+ int y,
+ browser_mouse_state press,
+ browser_mouse_state click)
+{
+ bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);
+ bool ctrl = ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000);
+ bool alt = ((GetKeyState(VK_MENU) & 0x8000) == 0x8000);
+
+ if ((gw == NULL) ||
+ (gw->mouse == NULL) ||
+ (gw->bw == NULL))
+ return 0;
+
+ LOG("state 0x%x, press 0x%x", gw->mouse->state, press);
+ if ((gw->mouse->state & press) != 0) {
+ gw->mouse->state &= ~press;
+ gw->mouse->state |= click;
+ }
+
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_1) != 0) && !shift)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_1;
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_2) != 0) && !ctrl)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_2;
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_3) != 0) && !alt)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_3;
+
+ if ((gw->mouse->state & click) != 0) {
+ LOG("mouse click bw %p, state 0x%x, x %f, y %f", gw->bw, gw->mouse->state, (x + gw->scrollx) / gw->scale, (y + gw->scrolly) / gw->scale);
+
+ browser_window_mouse_click(gw->bw,
+ gw->mouse->state,
+ (x + gw->scrollx) / gw->scale,
+ (y + gw->scrolly) / gw->scale);
+ } else {
+ browser_window_mouse_track(gw->bw,
+ 0,
+ (x + gw->scrollx) / gw->scale,
+ (y + gw->scrolly) / gw->scale);
+ }
+
+ gw->mouse->state = 0;
+ return 0;
+}
+
+
+/**
+ * Handle mouse button down messages.
+ */
+static LRESULT
+nsws_drawable_mousedown(struct gui_window *gw,
+ int x, int y,
+ browser_mouse_state button)
+{
+ if ((gw == NULL) ||
+ (gw->mouse == NULL) ||
+ (gw->bw == NULL)) {
+ nsws_localhistory_close(gw);
+ return 0;
+ }
+
+ gw->mouse->state = button;
+ if ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000)
+ gw->mouse->state |= BROWSER_MOUSE_MOD_1;
+ if ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000)
+ gw->mouse->state |= BROWSER_MOUSE_MOD_2;
+ if ((GetKeyState(VK_MENU) & 0x8000) == 0x8000)
+ gw->mouse->state |= BROWSER_MOUSE_MOD_3;
+
+ gw->mouse->pressed_x = (x + gw->scrollx) / gw->scale;
+ gw->mouse->pressed_y = (y + gw->scrolly) / gw->scale;
+
+ LOG("mouse click bw %p, state %x, x %f, y %f", gw->bw, gw->mouse->state, (x + gw->scrollx) / gw->scale, (y + gw->scrolly) / gw->scale);
+
+ browser_window_mouse_click(gw->bw, gw->mouse->state,
+ (x + gw->scrollx) / gw->scale,
+ (y + gw->scrolly) / gw->scale);
+
+ return 0;
+}
+
+/**
+ * Handle mouse movement messages.
+ */
+static LRESULT
+nsws_drawable_mousemove(struct gui_window *gw, int x, int y)
+{
+ bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);
+ bool ctrl = ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000);
+ bool alt = ((GetKeyState(VK_MENU) & 0x8000) == 0x8000);
+
+ if ((gw == NULL) || (gw->mouse == NULL) || (gw->bw == NULL))
+ return 0;
+
+ /* scale co-ordinates */
+ x = (x + gw->scrollx) / gw->scale;
+ y = (y + gw->scrolly) / gw->scale;
+
+ /* if mouse button held down and pointer moved more than
+ * minimum distance drag is happening */
+ if (((gw->mouse->state & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) != 0) &&
+ (abs(x - gw->mouse->pressed_x) >= 5) &&
+ (abs(y - gw->mouse->pressed_y) >= 5)) {
+
+ LOG("Drag start state 0x%x", gw->mouse->state);
+
+ if ((gw->mouse->state & BROWSER_MOUSE_PRESS_1) != 0) {
+ browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_1,
+ gw->mouse->pressed_x,
+ gw->mouse->pressed_y);
+ gw->mouse->state &= ~BROWSER_MOUSE_PRESS_1;
+ gw->mouse->state |= BROWSER_MOUSE_HOLDING_1 |
+ BROWSER_MOUSE_DRAG_ON;
+ }
+ else if ((gw->mouse->state & BROWSER_MOUSE_PRESS_2) != 0) {
+ browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_2,
+ gw->mouse->pressed_x,
+ gw->mouse->pressed_y);
+ gw->mouse->state &= ~BROWSER_MOUSE_PRESS_2;
+ gw->mouse->state |= BROWSER_MOUSE_HOLDING_2 |
+ BROWSER_MOUSE_DRAG_ON;
+ }
+ }
+
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_1) != 0) && !shift)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_1;
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_2) != 0) && !ctrl)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_2;
+ if (((gw->mouse->state & BROWSER_MOUSE_MOD_3) != 0) && !alt)
+ gw->mouse->state &= ~BROWSER_MOUSE_MOD_3;
+
+
+ browser_window_mouse_track(gw->bw, gw->mouse->state, x, y);
+
+ return 0;
+}
+
+/**
+ * Called when activity occours within the drawable window.
+ */
+static LRESULT CALLBACK
+nsws_window_drawable_event_callback(HWND hwnd,
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ struct gui_window *gw;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ gw = nsws_get_gui_window(hwnd);
+ if (gw == NULL) {
+ LOG("Unable to find gui window structure for hwnd %p", hwnd);
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ switch(msg) {
+
+ case WM_MOUSEMOVE:
+ return nsws_drawable_mousemove(gw,
+ GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam));
+
+ case WM_LBUTTONDOWN:
+ nsws_drawable_mousedown(gw,
+ GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam),
+ BROWSER_MOUSE_PRESS_1);
+ SetFocus(hwnd);
+ nsws_localhistory_close(gw);
+ return 0;
+ break;
+
+ case WM_RBUTTONDOWN:
+ nsws_drawable_mousedown(gw,
+ GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam),
+ BROWSER_MOUSE_PRESS_2);
+ SetFocus(hwnd);
+ return 0;
+ break;
+
+ case WM_LBUTTONUP:
+ return nsws_drawable_mouseup(gw,
+ GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam),
+ BROWSER_MOUSE_PRESS_1,
+ BROWSER_MOUSE_CLICK_1);
+
+ case WM_RBUTTONUP:
+ return nsws_drawable_mouseup(gw,
+ GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam),
+ BROWSER_MOUSE_PRESS_2,
+ BROWSER_MOUSE_CLICK_2);
+
+ case WM_ERASEBKGND: /* ignore as drawable window is redrawn on paint */
+ return 0;
+
+ case WM_PAINT: /* redraw the exposed part of the window */
+ return nsws_drawable_paint(gw, hwnd);
+
+ case WM_KEYDOWN:
+ return nsws_drawable_key(gw, hwnd, wparam);
+
+ case WM_SIZE:
+ return nsws_drawable_resize(gw);
+
+ case WM_HSCROLL:
+ return nsws_drawable_hscroll(gw, hwnd, wparam);
+
+ case WM_VSCROLL:
+ return nsws_drawable_vscroll(gw, hwnd, wparam);
+
+ case WM_MOUSEWHEEL:
+ return nsws_drawable_wheel(gw, hwnd, wparam);
+
+ }
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+/**
+ * Create a drawable window.
+ */
+HWND
+nsws_window_create_drawable(HINSTANCE hinstance,
+ HWND hparent,
+ struct gui_window *gw)
+{
+ HWND hwnd;
+ hwnd = CreateWindow(windowclassname_drawable,
+ NULL,
+ WS_VISIBLE | WS_CHILD,
+ 0, 0, 0, 0,
+ hparent,
+ NULL,
+ hinstance,
+ NULL);
+
+ if (hwnd == NULL) {
+ win_perror("WindowCreateDrawable");
+ LOG("Window creation failed");
+ return NULL;
+ }
+
+ /* set the gui window associated with this toolbar */
+ SetProp(hwnd, TEXT("GuiWnd"), (HANDLE)gw);
+
+ return hwnd;
+}
+
+/**
+ * Create the drawable window class.
+ */
+nserror
+nsws_create_drawable_class(HINSTANCE hinstance) {
+ nserror ret = NSERROR_OK;
+ WNDCLASSEX w;
+
+ /* drawable area */
+ w.cbSize = sizeof(WNDCLASSEX);
+ w.style = 0;
+ w.lpfnWndProc = nsws_window_drawable_event_callback;
+ w.cbClsExtra = 0;
+ w.cbWndExtra = 0;
+ w.hInstance = hinstance;
+ w.hIcon = NULL;
+ w.hCursor = NULL;
+ w.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
+ w.lpszMenuName = NULL;
+ w.lpszClassName = windowclassname_drawable;
+ w.hIconSm = NULL;
+
+ if (RegisterClassEx(&w) == 0) {
+ win_perror("DrawableClass");
+ ret = NSERROR_INIT_FAILED;
+ }
+
+ return ret;
+}
diff --git a/frontends/windows/drawable.h b/frontends/windows/drawable.h
new file mode 100644
index 000000000..e770f94b2
--- /dev/null
+++ b/frontends/windows/drawable.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_DRAWABLE_H_
+#define _NETSURF_WINDOWS_DRAWABLE_H_
+
+nserror nsws_create_drawable_class(HINSTANCE hinstance);
+HWND nsws_window_create_drawable(HINSTANCE hinstance, HWND hparent, struct gui_window *gw);
+
+#endif /* _NETSURF_WINDOWS_DRAWABLE_H_ */
diff --git a/frontends/windows/file.c b/frontends/windows/file.c
new file mode 100644
index 000000000..e9eb9caf9
--- /dev/null
+++ b/frontends/windows/file.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2014, 2015 Vincent Sanders <vince@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
+ * Windows file operation table implementation.
+ */
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <windows.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/corestrings.h"
+#include "utils/url.h"
+#include "utils/file.h"
+#include "utils/string.h"
+#include "desktop/browser.h"
+
+#include "windows/file.h"
+
+/**
+ * Generate a windows path from one or more component elemnts.
+ *
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nelm The number of elements.
+ * @param[in] ap The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror windows_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
+{
+ return vsnstrjoin(str, size, '\\', nelm, ap);
+}
+
+
+/**
+ * Get the basename of a file using windows path handling.
+ *
+ * This gets the last element of a path and returns it.
+ *
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror windows_basename(const char *path, char **str, size_t *size)
+{
+ const char *leafname;
+ char *fname;
+
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ leafname = strrchr(path, '\\');
+ if (!leafname) {
+ leafname = path;
+ } else {
+ leafname += 1;
+ }
+
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Create a path from a nsurl using windows file handling.
+ *
+ * @param[in] url The url to encode.
+ * @param[out] path_out A string containing the result path which should
+ * be freed by the caller.
+ * @return NSERROR_OK and the path is written to \a path or error code
+ * on faliure.
+ */
+static nserror windows_nsurl_to_path(struct nsurl *url, char **path_out)
+{
+ lwc_string *urlpath;
+ char *path;
+ bool match;
+ lwc_string *scheme;
+ nserror res;
+
+ if ((url == NULL) || (path_out == NULL)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
+ &match) != lwc_error_ok)
+ {
+ return NSERROR_BAD_PARAMETER;
+ }
+ lwc_string_unref(scheme);
+ if (match == false) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ urlpath = nsurl_get_component(url, NSURL_PATH);
+ if (urlpath == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ res = url_unescape(lwc_string_data(urlpath), &path);
+ lwc_string_unref(urlpath);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* if there is a drive: prefix treat path as DOS filename */
+ if ((path[2] == ':') || (path[2] == '|')) {
+ char *sidx; /* slash index */
+
+ /* move the string down to remove leading / note the
+ * strlen is *not* copying too much data as we are
+ * moving the null too!
+ */
+ memmove(path, path + 1, strlen(path));
+
+ /* swap / for \ */
+ sidx = strrchr(path, '/');
+ while (sidx != NULL) {
+ *sidx = '\\';
+ sidx = strrchr(path, '/');
+ }
+ }
+ /* if the path does not have a drive letter we return the
+ * complete path.
+ */
+ /** @todo Need to check returning the unaltered path in this
+ * case is correct
+ */
+
+ *path_out = path;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Create a nsurl from a path using windows file handling.
+ *
+ * Perform the necessary operations on a path to generate a nsurl.
+ *
+ * @param[in] path The path to convert.
+ * @param[out] url_out pointer to recive the nsurl, The returned url
+ * should be unreferenced by the caller.
+ * @return NSERROR_OK and the url is placed in \a url or error code on
+ * faliure.
+ */
+static nserror windows_path_to_nsurl(const char *path, struct nsurl **url_out)
+{
+ nserror ret;
+ int urllen;
+ char *urlstr;
+ char *sidx; /* slash index */
+
+ if ((path == NULL) || (url_out == NULL) || (*path == 0)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* build url as a string for nsurl constructor */
+ urllen = strlen(path) + FILE_SCHEME_PREFIX_LEN + 5;
+ urlstr = malloc(urllen);
+ if (urlstr == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /** @todo check if this should be url escaping the path. */
+ if (*path == '/') {
+ /* unix style path start, so try wine Z: */
+ snprintf(urlstr, urllen, "%sZ%%3A%s", FILE_SCHEME_PREFIX, path);
+ } else {
+ snprintf(urlstr, urllen, "%s%s", FILE_SCHEME_PREFIX, path);
+ }
+
+ sidx = strrchr(urlstr, '\\');
+ while (sidx != NULL) {
+ *sidx = '/';
+ sidx = strrchr(urlstr, '\\');
+ }
+
+ ret = nsurl_create(urlstr, url_out);
+ free(urlstr);
+
+ return ret;
+}
+
+
+/**
+ * Ensure that all directory elements needed to store a filename exist.
+ *
+ * @param fname The filename to ensure the path to exists.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+static nserror windows_mkdir_all(const char *fname)
+{
+ char *dname;
+ char *sep;
+ struct stat sb;
+
+ dname = strdup(fname);
+
+ sep = strrchr(dname, '\\');
+ if (sep == NULL) {
+ /* no directory separator path is just filename so its ok */
+ free(dname);
+ return NSERROR_OK;
+ }
+
+ *sep = 0; /* null terminate directory path */
+
+ if (stat(dname, &sb) == 0) {
+ free(dname);
+ if (S_ISDIR(sb.st_mode)) {
+ /* path to file exists and is a directory */
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_DIRECTORY;
+ }
+ *sep = '\\'; /* restore separator */
+
+ sep = dname;
+ while (*sep == '\\') {
+ sep++;
+ }
+ while ((sep = strchr(sep, '\\')) != NULL) {
+ *sep = 0;
+ if (stat(dname, &sb) != 0) {
+ if (nsmkdir(dname, S_IRWXU) != 0) {
+ /* could not create path element */
+ free(dname);
+ return NSERROR_NOT_FOUND;
+ }
+ } else {
+ if (! S_ISDIR(sb.st_mode)) {
+ /* path element not a directory */
+ free(dname);
+ return NSERROR_NOT_DIRECTORY;
+ }
+ }
+ *sep = '\\'; /* restore separator */
+ /* skip directory separators */
+ while (*sep == '\\') {
+ sep++;
+ }
+ }
+
+ free(dname);
+ return NSERROR_OK;
+}
+
+/* windows file handling */
+static struct gui_file_table file_table = {
+ .mkpath = windows_mkpath,
+ .basename = windows_basename,
+ .nsurl_to_path = windows_nsurl_to_path,
+ .path_to_nsurl = windows_path_to_nsurl,
+ .mkdir_all = windows_mkdir_all,
+};
+
+struct gui_file_table *win32_file_table = &file_table;
diff --git a/frontends/windows/file.h b/frontends/windows/file.h
new file mode 100644
index 000000000..5262dde2c
--- /dev/null
+++ b/frontends/windows/file.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Vincent Sanders <vince@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
+ * Windows file operation table interface.
+ */
+
+#ifndef _NETSURF_WINDOWS_FILE_H_
+#define _NETSURF_WINDOWS_FILE_H_
+
+struct gui_file_table *win32_file_table;
+
+#endif
diff --git a/frontends/windows/filetype.c b/frontends/windows/filetype.c
new file mode 100644
index 000000000..b06534d6a
--- /dev/null
+++ b/frontends/windows/filetype.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003 James Bursa <bursa@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/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "content/fetch.h"
+#include "desktop/gui_fetch.h"
+
+#include "windows/filetype.h"
+
+/**
+ * filetype -- determine the MIME type of a local file
+ */
+static const char *fetch_filetype(const char *unix_path)
+{
+ int l;
+ LOG("unix path %s", unix_path);
+ l = strlen(unix_path);
+ if (2 < l && strcasecmp(unix_path + l - 3, "css") == 0)
+ return "text/css";
+ if (2 < l && strcasecmp(unix_path + l - 3, "jpg") == 0)
+ return "image/jpeg";
+ if (3 < l && strcasecmp(unix_path + l - 4, "jpeg") == 0)
+ return "image/jpeg";
+ if (2 < l && strcasecmp(unix_path + l - 3, "gif") == 0)
+ return "image/gif";
+ if (2 < l && strcasecmp(unix_path + l - 3, "png") == 0)
+ return "image/png";
+ if (2 < l && strcasecmp(unix_path + l - 3, "jng") == 0)
+ return "image/jng";
+ if (2 < l && strcasecmp(unix_path + l - 3, "svg") == 0)
+ return "image/svg";
+ if (2 < l && strcasecmp(unix_path + l - 3, "bmp") == 0)
+ return "image/x-ms-bmp";
+ return "text/html";
+}
+
+static struct gui_fetch_table fetch_table = {
+ .filetype = fetch_filetype,
+};
+
+struct gui_fetch_table *win32_fetch_table = &fetch_table;
diff --git a/frontends/windows/filetype.h b/frontends/windows/filetype.h
new file mode 100644
index 000000000..f71a0b2da
--- /dev/null
+++ b/frontends/windows/filetype.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_FILETYPE_H_
+#define _NETSURF_WINDOWS_FILETYPE_H_
+
+struct gui_fetch_table *win32_fetch_table;
+
+#endif
diff --git a/frontends/windows/findfile.c b/frontends/windows/findfile.c
new file mode 100644
index 000000000..8c8906a80
--- /dev/null
+++ b/frontends/windows/findfile.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include <winsock2.h>
+#include <windows.h>
+
+#include <limits.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <curl/curl.h>
+
+#include "utils/log.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+#include "utils/filepath.h"
+
+#include "windows/findfile.h"
+
+/** Create an array of valid paths to search for resources.
+ *
+ * The idea is that all the complex path computation to find resources
+ * is performed here, once, rather than every time a resource is
+ * searched for.
+ */
+char **
+nsws_init_resource(const char *resource_path)
+{
+ char **pathv; /* resource path string vector */
+ char **respath; /* resource paths vector */
+ const char *lang = NULL;
+ char *winpath;
+ int pathi;
+ char *slsh;
+
+ pathv = filepath_path_to_strvec(resource_path);
+ if (pathv == NULL)
+ return NULL;
+
+ winpath = malloc(MAX_PATH);
+ GetModuleFileName(NULL, winpath, MAX_PATH);
+ slsh = strrchr(winpath, '\\');
+ if (slsh != NULL)
+ *slsh=0;
+ strncat(winpath, "\\windows\\res", MAX_PATH);
+
+ pathi = 0;
+ while (pathv[pathi] != NULL)
+ pathi++;
+ pathv[pathi] = winpath;
+
+ respath = filepath_generate(pathv, &lang);
+
+ filepath_free_strvec(pathv);
+
+ return respath;
+}
+
+static char *realpath(const char *path, char *resolved_path)
+{
+ /* useless, but there we go */
+ return strncpy(resolved_path, path, PATH_MAX);
+}
+
+
+/**
+ * Locate a shared resource file by searching known places in order.
+ *
+ * Search order is: ~/.netsurf/, $NETSURFRES/ (where NETSURFRES is an
+ * environment variable), then the path specified in
+ * NETSURF_WINDOWS_RESPATH in the Makefile then .\\res\\ [windows paths]
+ *
+ * \param buf buffer to write to. must be at least PATH_MAX chars
+ * \param filename file to look for
+ * \param def default to return if file not found
+ * \return The passed in buffer
+ */
+
+char *nsws_find_resource(char *buf, const char *filename, const char *def)
+{
+ char *cdir = getenv("HOME");
+ char t[PATH_MAX];
+
+ if (cdir != NULL) {
+ LOG("Found Home %s", cdir);
+ strcpy(t, cdir);
+ strcat(t, "/.netsurf/");
+ strcat(t, filename);
+ if ((realpath(t, buf) != NULL) && (access(buf, R_OK) == 0))
+ return buf;
+ }
+
+ cdir = getenv("NETSURFRES");
+
+ if (cdir != NULL) {
+ if (realpath(cdir , buf) != NULL) {
+ strcat(buf, "/");
+ strcat(buf, filename);
+ if (access(buf, R_OK) == 0)
+ return buf;
+ }
+ }
+
+ strcpy(t, NETSURF_WINDOWS_RESPATH);
+ strcat(t, filename);
+ if ((realpath(t, buf) != NULL) && (access(buf, R_OK) == 0))
+ return buf;
+
+ getcwd(t, PATH_MAX - SLEN("\\res\\") - strlen(filename));
+ strcat(t, "\\res\\");
+ strcat(t, filename);
+ LOG("looking in %s", t);
+ if ((realpath(t, buf) != NULL) && (access(buf, R_OK) == 0))
+ return buf;
+
+ if (def[0] == '~') {
+ snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1);
+ if (realpath(t, buf) == NULL) {
+ strcpy(buf, t);
+ }
+ } else {
+ if (realpath(def, buf) == NULL) {
+ strcpy(buf, def);
+ }
+ }
+
+ return buf;
+}
+
+
+/*
+ * Local Variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/frontends/windows/findfile.h b/frontends/windows/findfile.h
new file mode 100644
index 000000000..808adc8ef
--- /dev/null
+++ b/frontends/windows/findfile.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Daniel Silverstone <dsilvers@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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_FINDFILE_H_
+#define _NETSURF_WINDOWS_FINDFILE_H_
+
+extern char *nsws_find_resource(char *buf, const char *filename, const char *def);
+
+char **nsws_init_resource(const char *resource_path);
+
+#endif /* _NETSURF_WINDOWS_FINDFILE_H_ */
diff --git a/frontends/windows/font.c b/frontends/windows/font.c
new file mode 100644
index 000000000..f67205a6f
--- /dev/null
+++ b/frontends/windows/font.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2009 - 2014 Vincent Sanders <vince@netsurf-browser.org>
+ * Copyright 2009 - 2013 Michael Drake <tlsa@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
+ * Windows font handling implementation.
+ */
+
+#include "utils/config.h"
+#include <inttypes.h>
+#include <assert.h>
+#include <windows.h>
+
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "utils/utf8.h"
+#include "desktop/gui_layout.h"
+#include "desktop/gui_utf8.h"
+
+#include "windows/font.h"
+
+HWND font_hwnd;
+
+nserror utf8_to_font_encoding(const struct font_desc* font,
+ const char *string,
+ size_t len,
+ char **result)
+{
+ return utf8_to_enc(string, font->encoding, len, result);
+}
+
+static nserror utf8_to_local_encoding(const char *string,
+ size_t len,
+ char **result)
+{
+ return utf8_to_enc(string, "UCS-2", len, result);
+}
+
+static nserror utf8_from_local_encoding(const char *string, size_t len,
+ char **result)
+{
+ assert(string && result);
+
+ if (len == 0)
+ len = strlen(string);
+
+ *result = strndup(string, len);
+ if (!(*result))
+ return NSERROR_NOMEM;
+
+ return NSERROR_OK;
+}
+
+HFONT get_font(const plot_font_style_t *style)
+{
+ char *face = NULL;
+ DWORD family;
+ switch(style->family) {
+ case PLOT_FONT_FAMILY_SERIF:
+ face = strdup(nsoption_charp(font_serif));
+ family = FF_ROMAN | DEFAULT_PITCH;
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ face = strdup(nsoption_charp(font_mono));
+ family = FF_MODERN | DEFAULT_PITCH;
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ face = strdup(nsoption_charp(font_cursive));
+ family = FF_SCRIPT | DEFAULT_PITCH;
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ face = strdup(nsoption_charp(font_fantasy));
+ family = FF_DECORATIVE | DEFAULT_PITCH;
+ break;
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ default:
+ face = strdup(nsoption_charp(font_sans));
+ family = FF_SWISS | DEFAULT_PITCH;
+ break;
+ }
+
+ int nHeight = -10;
+
+ HDC hdc = GetDC(font_hwnd);
+ nHeight = -MulDiv(style->size, GetDeviceCaps(hdc, LOGPIXELSY), 72 * FONT_SIZE_SCALE);
+ ReleaseDC(font_hwnd, hdc);
+
+ HFONT font = CreateFont(
+ nHeight, /* height */
+ 0, /* width */
+ 0, /* escapement*/
+ 0, /* orientation */
+ style->weight,
+ (style->flags & FONTF_ITALIC) ? TRUE : FALSE,
+ FALSE, /* underline */
+ FALSE, /* strike */
+ DEFAULT_CHARSET, /* for locale */
+ OUT_DEFAULT_PRECIS, /* general 'best match' */
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ family,
+ face /* name of font face */
+ );
+ if (face != NULL)
+ free(face);
+
+ if (font == NULL) {
+ if (style->family == PLOT_FONT_FAMILY_MONOSPACE)
+ font = (HFONT) GetStockObject(ANSI_FIXED_FONT);
+ else
+ font = (HFONT) GetStockObject(ANSI_VAR_FONT);
+ }
+ if (font == NULL)
+ font = (HFONT) GetStockObject(SYSTEM_FONT);
+ return font;
+}
+
+/**
+ * Measure the width of a string.
+ *
+ * \param[in] style plot style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[out] width updated to width of string[0..length)
+ * \return true on success and width updated else false
+ */
+static nserror
+win32_font_width(const plot_font_style_t *style,
+ const char *string,
+ size_t length,
+ int *width)
+{
+ HDC hdc;
+ HFONT font;
+ HFONT fontbak;
+ SIZE s;
+ bool ret = true;
+
+ if (length == 0) {
+ *width = 0;
+ } else {
+ hdc = GetDC(NULL);
+ font = get_font(style);
+ fontbak = SelectObject(hdc, font);
+
+ /* may well need to convert utf-8 to lpctstr */
+ if (GetTextExtentPoint32A(hdc, string, length, &s) != 0) {
+ *width = s.cx;
+ } else {
+ ret = false;
+ }
+ font = SelectObject(hdc, fontbak);
+ DeleteObject(font);
+ ReleaseDC(NULL, hdc);
+ }
+ return ret;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param style css_style for this text, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate to search for
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+static nserror
+win32_font_position(const plot_font_style_t *style,
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
+{
+ HDC hdc;
+ HFONT font;
+ HFONT fontbak;
+ SIZE s;
+ int offset;
+ bool ret = true;
+
+ if ((length == 0) || (x < 1)) {
+ *char_offset = 0;
+ *actual_x = 0;
+ } else {
+ hdc = GetDC(NULL);
+ font = get_font(style);
+ fontbak = SelectObject(hdc, font);
+
+ if ((GetTextExtentExPointA(hdc, string, length, x, &offset, NULL,&s) != 0) &&
+ (GetTextExtentPoint32A(hdc, string, offset, &s) != 0)) {
+ *char_offset = (size_t)offset;
+ *actual_x = s.cx;
+ } else {
+ ret = false;
+ }
+ font = SelectObject(hdc, fontbak);
+ DeleteObject(font);
+ ReleaseDC(NULL, hdc);
+ }
+
+ return ret;
+}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param style css_style for this text, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x width available
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ *
+ * On exit, [char_offset == 0 ||
+ * string[char_offset] == ' ' ||
+ * char_offset == length]
+ */
+static nserror
+win32_font_split(const plot_font_style_t *style,
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
+{
+ int c_off;
+ bool ret = false;
+
+ if (win32_font_position(style, string, length, x, char_offset, actual_x)) {
+ c_off = *char_offset;
+ if (*char_offset == length) {
+ ret = true;
+ } else {
+ while ((string[*char_offset] != ' ') &&
+ (*char_offset > 0)) {
+ (*char_offset)--;
+ }
+
+ if (*char_offset == 0) {
+ *char_offset = c_off;
+ while ((*char_offset < length) &&
+ (string[*char_offset] != ' ')) {
+ (*char_offset)++;
+ }
+ }
+
+ ret = win32_font_width(style, string, *char_offset, actual_x);
+ }
+ }
+
+/*
+ LOG("ret %d Split %u chars at %ipx: Split at char %i (%ipx) - %.*s",
+ ret, length, x, *char_offset, *actual_x, *char_offset, string);
+*/
+ return ret;
+}
+
+
+static struct gui_layout_table layout_table = {
+ .width = win32_font_width,
+ .position = win32_font_position,
+ .split = win32_font_split,
+};
+
+struct gui_layout_table *win32_layout_table = &layout_table;
+
+
+static struct gui_utf8_table utf8_table = {
+ .utf8_to_local = utf8_to_local_encoding,
+ .local_to_utf8 = utf8_from_local_encoding,
+};
+
+struct gui_utf8_table *win32_utf8_table = &utf8_table;
diff --git a/frontends/windows/font.h b/frontends/windows/font.h
new file mode 100644
index 000000000..f2128afc5
--- /dev/null
+++ b/frontends/windows/font.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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
+ * The interface to the win32 font and utf8 handling.
+ */
+
+#ifndef _NETSURF_WINDOWS_FONT_H_
+#define _NETSURF_WINDOWS_FONT_H_
+
+extern HWND font_hwnd;
+
+struct font_desc {
+ const char *name;
+ int width, height;
+ const char *encoding;
+};
+
+struct gui_layout_table *win32_layout_table;
+struct gui_utf8_table *win32_utf8_table;
+
+extern nserror utf8_to_font_encoding(const struct font_desc* font,
+ const char *string,
+ size_t len,
+ char **result);
+
+/**
+ * generate a win32 font handle from a generic font style
+ *
+ * \param style The font style.
+ * \return The win32 font handle
+ */
+HFONT get_font(const plot_font_style_t *style);
+
+#endif /* NETSURF_WINDOWS_FONT_H */
+
diff --git a/frontends/windows/gui.c b/frontends/windows/gui.c
new file mode 100644
index 000000000..9923ecfaa
--- /dev/null
+++ b/frontends/windows/gui.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <windows.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/corestrings.h"
+#include "utils/url.h"
+#include "utils/file.h"
+#include "utils/messages.h"
+#include "desktop/browser.h"
+#include "desktop/gui_clipboard.h"
+
+#include "windows/schedule.h"
+#include "windows/window.h"
+#include "windows/filetype.h"
+#include "windows/gui.h"
+
+static bool win32_quit = false;
+
+HINSTANCE hInstance; /** win32 application instance handle. */
+
+
+void win32_set_quit(bool q)
+{
+ win32_quit = q;
+}
+
+/* exported interface documented in gui.h */
+void win32_run(void)
+{
+ MSG Msg; /* message from system */
+ BOOL bRet; /* message fetch result */
+ int timeout; /* timeout in miliseconds */
+ UINT timer_id = 0;
+
+ LOG("Starting messgae dispatcher");
+
+ while (!win32_quit) {
+ /* run the scheduler and discover how long to wait for
+ * the next event.
+ */
+ timeout = schedule_run();
+
+ if (timeout == 0) {
+ bRet = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE);
+ } else {
+ if (timeout > 0) {
+ /* set up a timer to ensure we get woken */
+ timer_id = SetTimer(NULL, 0, timeout, NULL);
+ }
+
+ /* wait for a message */
+ bRet = GetMessage(&Msg, NULL, 0, 0);
+
+ /* if a timer was sucessfully created remove it */
+ if (timer_id != 0) {
+ KillTimer(NULL, timer_id);
+ timer_id = 0;
+ }
+ }
+
+ if (bRet > 0) {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+ }
+}
+
+
+/* exported function documented in windows/gui.h */
+nserror win32_warning(const char *warning, const char *detail)
+{
+ size_t len = 1 + ((warning != NULL) ? strlen(messages_get(warning)) :
+ 0) + ((detail != 0) ? strlen(detail) : 0);
+ char message[len];
+ snprintf(message, len, messages_get(warning), detail);
+ MessageBox(NULL, message, "Warning", MB_ICONWARNING);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Core asks front end for clipboard contents.
+ *
+ * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
+ * \param length Byte length of UTF-8 text in buffer
+ */
+static void gui_get_clipboard(char **buffer, size_t *length)
+{
+ /* TODO: Implement this */
+ HANDLE clipboard_handle;
+ char *content;
+
+ clipboard_handle = GetClipboardData(CF_TEXT);
+ if (clipboard_handle != NULL) {
+ content = GlobalLock(clipboard_handle);
+ LOG("pasting %s", content);
+ GlobalUnlock(clipboard_handle);
+ }
+}
+
+
+/**
+ * Core tells front end to put given text in clipboard
+ *
+ * \param buffer UTF-8 text, owned by core
+ * \param length Byte length of UTF-8 text in buffer
+ * \param styles Array of styles given to text runs, owned by core, or NULL
+ * \param n_styles Number of text run styles in array
+ */
+static void gui_set_clipboard(const char *buffer, size_t length,
+ nsclipboard_styles styles[], int n_styles)
+{
+ /* TODO: Implement this */
+ HANDLE hnew;
+ char *new, *original;
+ HANDLE h = GetClipboardData(CF_TEXT);
+ if (h == NULL)
+ original = (char *)"";
+ else
+ original = GlobalLock(h);
+
+ size_t len = strlen(original) + 1;
+ hnew = GlobalAlloc(GHND, length + len);
+ new = (char *)GlobalLock(hnew);
+ snprintf(new, length + len, "%s%s", original, buffer);
+
+ if (h != NULL) {
+ GlobalUnlock(h);
+ EmptyClipboard();
+ }
+ GlobalUnlock(hnew);
+ SetClipboardData(CF_TEXT, hnew);
+}
+
+
+
+static struct gui_clipboard_table clipboard_table = {
+ .get = gui_get_clipboard,
+ .set = gui_set_clipboard,
+};
+
+struct gui_clipboard_table *win32_clipboard_table = &clipboard_table;
+
+
diff --git a/frontends/windows/gui.h b/frontends/windows/gui.h
new file mode 100644
index 000000000..4c3f360b1
--- /dev/null
+++ b/frontends/windows/gui.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_GUI_H_
+#define _NETSURF_WINDOWS_GUI_H_
+
+struct gui_window;
+struct gui_clipboard_table *win32_clipboard_table;
+
+extern HINSTANCE hInstance;
+
+extern char *options_file_location;
+
+/* bounding box */
+typedef struct bbox_s {
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+} bbox_t;
+
+/**
+ * Run the win32 message loop with scheduling
+ */
+void win32_run(void);
+
+/**
+ * cause the main message loop to exit
+ */
+void win32_set_quit(bool q);
+
+/**
+ * Warn the user of an event.
+ *
+ * \param[in] message A warning looked up in the message translation table
+ * \param[in] detail Additional text to be displayed or NULL.
+ * \return NSERROR_OK on success or error code if there was a
+ * faliure displaying the message to the user.
+ */
+nserror win32_warning(const char *warning, const char *detail);
+
+#endif
diff --git a/frontends/windows/localhistory.c b/frontends/windows/localhistory.c
new file mode 100644
index 000000000..674f198a0
--- /dev/null
+++ b/frontends/windows/localhistory.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include "utils/config.h"
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include "desktop/browser_history.h"
+#include "desktop/plotters.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+
+#include "windows/window.h"
+#include "windows/localhistory.h"
+#include "windows/gui.h"
+#include "windows/plot.h"
+#include "windows/resourceid.h"
+#include "windows/windbg.h"
+
+static const char windowclassname_localhistory[] = "nswslocalhistorywindow";
+
+struct nsws_localhistory {
+ HWND hwnd; /**< the window handle */
+ int width; /**< the width of the memory history */
+ int height; /**< the height of the memory history */
+ int guiwidth; /**< the width of the history window */
+ int guiheight; /**< the height of the history window */
+ int vscroll; /**< the vertical scroll location */
+ int hscroll; /**< the horizontal scroll location */
+};
+
+
+static void nsws_localhistory_scroll_check(struct nsws_localhistory *l, struct gui_window *gw)
+{
+ SCROLLINFO si;
+
+ if ((gw->bw == NULL) || (l->hwnd == NULL))
+ return;
+
+ browser_window_history_size(gw->bw, &(l->width), &(l->height));
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = l->height;
+ si.nPage = l->guiheight;
+ si.nPos = 0;
+ SetScrollInfo(l->hwnd, SB_VERT, &si, TRUE);
+
+ si.nMax = l->width;
+ si.nPage = l->guiwidth;
+ SetScrollInfo(l->hwnd, SB_HORZ, &si, TRUE);
+ if (l->guiheight >= l->height)
+ l->vscroll = 0;
+ if (l->guiwidth >= l->width)
+ l->hscroll = 0;
+ SendMessage(l->hwnd, WM_PAINT, 0, 0);
+}
+
+
+
+static void nsws_localhistory_up(struct nsws_localhistory *l, struct gui_window *gw)
+{
+ HDC tmp_hdc;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &win_plotters
+ };
+
+ LOG("gui window %p", gw);
+
+ l->vscroll = 0;
+ l->hscroll = 0;
+
+ if (gw->bw != NULL) {
+ /* set global HDC for the plotters */
+ tmp_hdc = plot_hdc;
+ plot_hdc = GetDC(l->hwnd);
+
+ browser_window_history_redraw(gw->bw, &ctx);
+
+ ReleaseDC(l->hwnd, plot_hdc);
+
+ plot_hdc = tmp_hdc;
+ }
+
+ nsws_localhistory_scroll_check(l, gw);
+}
+
+
+void nsws_localhistory_close(struct gui_window *w)
+{
+ struct nsws_localhistory *l = gui_window_localhistory(w);
+ if (l != NULL)
+ CloseWindow(l->hwnd);
+}
+
+static LRESULT CALLBACK
+nsws_localhistory_event_callback(HWND hwnd, UINT msg,
+ WPARAM wparam, LPARAM lparam)
+{
+ int x,y;
+ struct gui_window *gw;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ gw = nsws_get_gui_window(hwnd);
+ if (gw == NULL) {
+ LOG("Unable to find gui window structure for hwnd %p", hwnd);
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ switch(msg) {
+
+ case WM_CREATE:
+ nsws_localhistory_scroll_check(gw->localhistory, gw);
+ break;
+
+ case WM_SIZE:
+ gw->localhistory->guiheight = HIWORD(lparam);
+ gw->localhistory->guiwidth = LOWORD(lparam);
+ nsws_localhistory_scroll_check(gw->localhistory, gw);
+ break;
+
+ case WM_LBUTTONUP:
+ if (gw->bw == NULL)
+ break;
+
+ x = GET_X_LPARAM(lparam);
+ y = GET_Y_LPARAM(lparam);
+
+ if (browser_window_history_click(gw->bw,
+ gw->localhistory->hscroll + x,
+ gw->localhistory->vscroll + y,
+ false)) {
+ DestroyWindow(hwnd);
+ }
+
+ break;
+
+ case WM_MOUSEMOVE:
+ x = GET_X_LPARAM(lparam);
+ y = GET_Y_LPARAM(lparam);
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ break;
+
+
+ case WM_VSCROLL:
+ {
+ SCROLLINFO si;
+ int mem;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ mem = si.nPos;
+ switch (LOWORD(wparam)) {
+ case SB_TOP:
+ si.nPos = si.nMin;
+ break;
+ case SB_BOTTOM:
+ si.nPos = si.nMax;
+ break;
+ case SB_LINEUP:
+ si.nPos -= 30;
+ break;
+ case SB_LINEDOWN:
+ si.nPos += 30;
+ break;
+ case SB_PAGEUP:
+ si.nPos -= gw->localhistory->guiheight;
+ break;
+ case SB_PAGEDOWN:
+ si.nPos += gw->localhistory->guiheight;
+ break;
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+ default:
+ break;
+ }
+ si.nPos = min(si.nPos, gw->localhistory->height);
+ si.nPos = min(si.nPos, 0);
+ si.fMask = SIF_POS;
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ if (si.nPos != mem) {
+ gw->localhistory->vscroll += si.nPos - mem;
+ ScrollWindowEx(hwnd, 0, -(si.nPos - mem), NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
+ }
+ break;
+ }
+
+ case WM_HSCROLL:
+ {
+ SCROLLINFO si;
+ int mem;
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ mem = si.nPos;
+
+ switch (LOWORD(wparam)) {
+ case SB_LINELEFT:
+ si.nPos -= 30;
+ break;
+ case SB_LINERIGHT:
+ si.nPos += 30;
+ break;
+ case SB_PAGELEFT:
+ si.nPos -= gw->localhistory->guiwidth;
+ break;
+ case SB_PAGERIGHT:
+ si.nPos += gw->localhistory->guiwidth;
+ break;
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+ default:
+ break;
+ }
+ si.nPos = min(si.nPos, gw->localhistory->width);
+ si.nPos = max(si.nPos, 0);
+ si.fMask = SIF_POS;
+ SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ if (si.nPos != mem) {
+ gw->localhistory->hscroll += si.nPos - mem;
+ ScrollWindowEx(hwnd, -(si.nPos - mem), 0, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
+ }
+ break;
+ }
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdc, tmp_hdc;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &win_plotters
+ };
+
+ hdc = BeginPaint(hwnd, &ps);
+ if (gw->bw != NULL) {
+ /* set global HDC for the plotters */
+ tmp_hdc = plot_hdc;
+ plot_hdc = hdc;
+
+ browser_window_history_redraw_rectangle(gw->bw,
+ gw->localhistory->hscroll + ps.rcPaint.left,
+ gw->localhistory->vscroll + ps.rcPaint.top,
+ gw->localhistory->hscroll + (ps.rcPaint.right - ps.rcPaint.left),
+ gw->localhistory->vscroll + (ps.rcPaint.bottom - ps.rcPaint.top),
+ ps.rcPaint.left,
+ ps.rcPaint.top, &ctx);
+
+ plot_hdc = tmp_hdc;
+
+ }
+ EndPaint(hwnd, &ps);
+
+ break;
+ }
+
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ return 1;
+
+ case WM_DESTROY:
+ free(gw->localhistory);
+ gw->localhistory = NULL;
+ break;
+
+ default:
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+
+ }
+ return 0;
+}
+
+/* exported method documented in windows/localhistory.h */
+struct nsws_localhistory *nsws_window_create_localhistory(struct gui_window *gw)
+{
+ struct nsws_localhistory *localhistory;
+ INITCOMMONCONTROLSEX icc;
+ int margin = 50;
+ RECT r;
+
+ LOG("gui window %p", gw);
+
+ /* if we already have a window, just update and re-show it */
+ if (gw->localhistory != NULL) {
+ nsws_localhistory_up(gw->localhistory, gw);
+ UpdateWindow(gw->localhistory->hwnd);
+ ShowWindow(gw->localhistory->hwnd, SW_SHOWNORMAL);
+ return gw->localhistory;
+ }
+
+ localhistory = calloc(1, sizeof(struct nsws_localhistory));
+
+ if (localhistory == NULL) {
+ return NULL;
+ }
+ gw->localhistory = localhistory;
+
+ localhistory->width = 0;
+ localhistory->height = 0;
+
+ if (gw->bw != NULL) {
+ browser_window_history_size(gw->bw,
+ &(localhistory->width),
+ &(localhistory->height));
+ }
+
+ GetWindowRect(gw->main, &r);
+ SetWindowPos(gw->main, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE);
+
+ localhistory->guiwidth = min(r.right - r.left - margin,
+ localhistory->width + margin);
+ localhistory->guiheight = min(r.bottom - r.top - margin,
+ localhistory->height + margin);
+
+ icc.dwSize = sizeof(icc);
+ icc.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
+#if WINVER > 0x0501
+ icc.dwICC |= ICC_STANDARD_CLASSES;
+#endif
+ InitCommonControlsEx(&icc);
+
+
+ LOG("creating local history window for hInstance %p", hInstance);
+ localhistory->hwnd = CreateWindow(windowclassname_localhistory,
+ "NetSurf History",
+ WS_THICKFRAME | WS_HSCROLL |
+ WS_VSCROLL | WS_CLIPCHILDREN |
+ WS_CLIPSIBLINGS | WS_SYSMENU | CS_DBLCLKS,
+ r.left + margin/2,
+ r.top + margin/2,
+ localhistory->guiwidth,
+ localhistory->guiheight,
+ NULL, NULL, hInstance, NULL);
+
+ /* set the gui window associated with this browser */
+ SetProp(localhistory->hwnd, TEXT("GuiWnd"), (HANDLE)gw);
+
+ LOG("gui_window %p width %d height %d hwnd %p", gw, localhistory->guiwidth, localhistory->guiheight, localhistory->hwnd);
+
+ nsws_localhistory_up(localhistory, gw);
+ UpdateWindow(localhistory->hwnd);
+ ShowWindow(localhistory->hwnd, SW_SHOWNORMAL);
+
+ return localhistory;
+}
+
+/* exported method documented in windows/localhistory.h */
+nserror
+nsws_create_localhistory_class(HINSTANCE hinstance) {
+ nserror ret = NSERROR_OK;
+ WNDCLASSEX w;
+
+ /* localhistory window */
+ w.cbSize = sizeof(WNDCLASSEX);
+ w.style = 0;
+ w.lpfnWndProc = nsws_localhistory_event_callback;
+ w.cbClsExtra = 0;
+ w.cbWndExtra = 0;
+ w.hInstance = hinstance;
+ w.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
+ w.hCursor = LoadCursor(NULL, IDC_ARROW);
+ w.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ w.lpszMenuName = NULL;
+ w.lpszClassName = windowclassname_localhistory;
+ w.hIconSm = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
+
+ if (RegisterClassEx(&w) == 0) {
+ win_perror("DrawableClass");
+ ret = NSERROR_INIT_FAILED;
+ }
+
+ return ret;
+}
diff --git a/frontends/windows/localhistory.h b/frontends/windows/localhistory.h
new file mode 100644
index 000000000..b0ad07491
--- /dev/null
+++ b/frontends/windows/localhistory.h
@@ -0,0 +1,32 @@
+/*
+* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+*/
+
+#ifndef _NETSURF_WINDOWS_LOCALHISTORY_H_
+#define _NETSURF_WINDOWS_LOCALHISTORY_H_
+
+struct nsws_localhistory;
+
+void nsws_localhistory_open(struct gui_window *gw);
+void nsws_localhistory_close(struct gui_window *gw);
+
+/* creates localhistory window */
+struct nsws_localhistory *nsws_window_create_localhistory(struct gui_window *gw);
+
+nserror nsws_create_localhistory_class(HINSTANCE hinstance);
+
+#endif
diff --git a/frontends/windows/main.c b/frontends/windows/main.c
new file mode 100644
index 000000000..df64e487d
--- /dev/null
+++ b/frontends/windows/main.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#include "utils/config.h"
+
+#include <limits.h>
+#include <stdbool.h>
+#include <windows.h>
+#include <io.h>
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/filepath.h"
+#include "utils/file.h"
+#include "utils/nsurl.h"
+#include "utils/nsoption.h"
+#include "desktop/browser.h"
+#include "desktop/gui_fetch.h"
+#include "desktop/gui_misc.h"
+#include "desktop/netsurf.h"
+
+#include "windows/findfile.h"
+#include "windows/file.h"
+#include "windows/drawable.h"
+#include "windows/download.h"
+#include "windows/localhistory.h"
+#include "windows/window.h"
+#include "windows/schedule.h"
+#include "windows/font.h"
+#include "windows/filetype.h"
+#include "windows/pointers.h"
+#include "windows/bitmap.h"
+#include "windows/gui.h"
+
+static char **respaths; /** resource search path vector. */
+
+char *options_file_location;
+
+/**
+ * Cause an abnormal program termination.
+ *
+ * \note This never returns and is intended to terminate without any cleanup.
+ *
+ * \param error The message to display to the user.
+ */
+static void die(const char *error)
+{
+ exit(1);
+}
+
+
+static nsurl *gui_get_resource_url(const char *path)
+{
+ char buf[PATH_MAX];
+ nsurl *url = NULL;
+
+ netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url);
+
+ return url;
+}
+
+/**
+ * Ensures output logging stream is available
+ */
+static bool nslog_ensure(FILE *fptr)
+{
+ /* mwindows compile flag normally invalidates standard io unless
+ * already redirected
+ */
+ if (_get_osfhandle(fileno(fptr)) == -1) {
+ AllocConsole();
+ freopen("CONOUT$", "w", fptr);
+ }
+ return true;
+}
+
+/**
+ * Set option defaults for windows 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 */
+
+ /* locate CA bundle and set as default, cannot rely on curl
+ * compiled in default on windows.
+ */
+ DWORD res_len;
+ DWORD buf_tchar_size = PATH_MAX + 1;
+ DWORD buf_bytes_size = sizeof(TCHAR) * buf_tchar_size;
+ char *ptr = NULL;
+
+ char *buf;
+
+ buf = malloc(buf_bytes_size);
+ if (buf== NULL) {
+ return NSERROR_NOMEM;
+ }
+ buf[0] = '\0';
+
+ res_len = SearchPathA(NULL,
+ "ca-bundle.crt",
+ NULL,
+ buf_tchar_size,
+ buf,
+ &ptr);
+ if (res_len > 0) {
+ nsoption_setnull_charp(ca_bundle, strdup(buf));
+ }
+ free(buf);
+
+ /* ensure homepage option has a default */
+ nsoption_setnull_charp(homepage_url, strdup(NETSURF_HOMEPAGE));
+
+ return NSERROR_OK;
+}
+
+
+static struct gui_misc_table win32_misc_table = {
+ .schedule = win32_schedule,
+ .warning = win32_warning,
+};
+
+
+/**
+ * Entry point from windows
+ **/
+int WINAPI
+WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
+{
+ char **argv = NULL;
+ int argc = 0, argctemp = 0;
+ size_t len;
+ LPWSTR *argvw;
+ char *messages;
+ nserror ret;
+ const char *addr;
+ nsurl *url;
+ struct netsurf_table win32_table = {
+ .misc = &win32_misc_table,
+ .window = win32_window_table,
+ .clipboard = win32_clipboard_table,
+ .download = win32_download_table,
+ .fetch = win32_fetch_table,
+ .file = win32_file_table,
+ .utf8 = win32_utf8_table,
+ .bitmap = win32_bitmap_table,
+ .layout = win32_layout_table,
+ };
+ win32_fetch_table->get_resource_url = gui_get_resource_url;
+
+ ret = netsurf_register(&win32_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table registration failed");
+ }
+
+ if (SLEN(lpcli) > 0) {
+ argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
+ }
+
+ setbuf(stderr, NULL);
+
+ /* Construct a unix style argc/argv */
+ argv = malloc(sizeof(char *) * argc);
+ while (argctemp < argc) {
+ len = wcstombs(NULL, argvw[argctemp], 0) + 1;
+ if (len > 0) {
+ argv[argctemp] = malloc(len);
+ }
+
+ if (argv[argctemp] != NULL) {
+ wcstombs(argv[argctemp], argvw[argctemp], len);
+ /* alter windows-style forward slash flags to
+ * hyphen flags.
+ */
+ if (argv[argctemp][0] == '/')
+ argv[argctemp][0] = '-';
+ }
+ argctemp++;
+ }
+
+ respaths = nsws_init_resource("${APPDATA}\\NetSurf:${HOME}\\.netsurf:${NETSURFRES}:${PROGRAMFILES}\\NetSurf\\NetSurf\\:"NETSURF_WINDOWS_RESPATH);
+
+
+ options_file_location = filepath_find(respaths, "preferences");
+
+ /* 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);
+
+ /* message init */
+ messages = filepath_find(respaths, "messages");
+ messages_add_from_file(messages);
+ free(messages);
+
+ /* common initialisation */
+ ret = netsurf_init(NULL);
+ 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);
+ ret = nsws_create_localhistory_class(hInstance);
+
+ nsoption_set_bool(target_blank, false);
+
+ nsws_window_init_pointers(hInstance);
+
+ /* If there is a url specified on the command line use it */
+ if (argc > 1) {
+ addr = argv[1];
+ } else if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ } else {
+ addr = NETSURF_HOMEPAGE;
+ }
+
+ LOG("calling browser_window_create");
+
+ ret = nsurl_create(addr, &url);
+ if (ret == NSERROR_OK) {
+ ret = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+
+ }
+ if (ret != NSERROR_OK) {
+ win32_warning(messages_get_errorcode(ret), 0);
+ } else {
+ win32_run();
+ }
+
+ netsurf_exit();
+
+ free(options_file_location);
+
+ return 0;
+}
diff --git a/frontends/windows/plot.c b/frontends/windows/plot.c
new file mode 100644
index 000000000..86870ea4e
--- /dev/null
+++ b/frontends/windows/plot.c
@@ -0,0 +1,868 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include "utils/config.h"
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <windows.h>
+
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+#include "desktop/mouse.h"
+#include "desktop/gui_window.h"
+#include "desktop/plotters.h"
+
+#include "windows/bitmap.h"
+#include "windows/font.h"
+#include "windows/gui.h"
+#include "windows/plot.h"
+
+
+/* set NSWS_PLOT_DEBUG to 0 for no debugging, 1 for debugging */
+/* #define NSWS_PLOT_DEBUG */
+
+#ifdef NSWS_PLOT_DEBUG
+#define PLOT_LOG(x...) LOG(x)
+#else
+#define PLOT_LOG(x...) ((void) 0)
+#endif
+
+HDC plot_hdc;
+
+static RECT plot_clip; /* currently set clipping rectangle */
+
+static bool clip(const struct rect *clip)
+{
+ PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1);
+
+ plot_clip.left = clip->x0;
+ plot_clip.top = clip->y0;
+ plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */
+ plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */
+
+ return true;
+}
+
+static bool line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ /* windows 0x00bbggrr */
+ DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type ==
+ PLOT_OP_TYPE_DOT) ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH:
+ 0);
+ LOGBRUSH lb = {BS_SOLID, col, 0};
+ HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return false;
+ }
+ HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (bak == NULL) {
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+ return false;
+ }
+/*
+ RECT r;
+ r.left = x0;
+ r.top = y0;
+ r.right = x1;
+ r.bottom = y1;
+*/
+ SelectClipRgn(plot_hdc, clipregion);
+
+ MoveToEx(plot_hdc, x0, y0, (LPPOINT) NULL);
+
+ LineTo(plot_hdc, x1, y1);
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, bak);
+
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+
+ return true;
+}
+
+static bool rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ PLOT_LOG("rectangle from %d,%d to %d,%d", x0, y0, x1, y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ x1++;
+ y1++;
+
+ COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ DWORD penstyle = PS_GEOMETRIC |
+ (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH :
+ (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL :
+ 0)));
+ LOGBRUSH lb = {BS_SOLID, pencol, 0};
+ LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0};
+ if (style->fill_type == PLOT_OP_TYPE_NONE)
+ lb1.lbStyle = BS_HOLLOW;
+
+ HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
+ if (pen == NULL) {
+ return false;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(pen);
+ return false;
+ }
+ HBRUSH brush = CreateBrushIndirect(&lb1);
+ if (brush == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return false;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return false;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ Rectangle(plot_hdc, x0, y0, x1, y1);
+
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ SelectClipRgn(plot_hdc, NULL);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ DeleteObject(clipregion);
+
+ return true;
+}
+
+
+static bool polygon(const int *p, unsigned int n, const plot_style_t *style)
+{
+ PLOT_LOG("polygon %d points", n);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ POINT points[n];
+ unsigned int i;
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return false;
+ }
+ HPEN penbak = SelectObject(plot_hdc, pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return false;
+ }
+ HBRUSH brush = CreateSolidBrush(brushcol);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return false;
+ }
+ HBRUSH brushbak = SelectObject(plot_hdc, brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return false;
+ }
+ SetPolyFillMode(plot_hdc, WINDING);
+ for (i = 0; i < n; i++) {
+ points[i].x = (long) p[2 * i];
+ points[i].y = (long) p[2 * i + 1];
+
+ PLOT_LOG("%ld,%ld ", points[i].x, points[i].y);
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (n >= 2)
+ Polygon(plot_hdc, points, n);
+
+ SelectClipRgn(plot_hdc, NULL);
+
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return true;
+}
+
+
+static bool text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *style)
+{
+ PLOT_LOG("words %s at %d,%d", text, x, y);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ HFONT fontbak, font = get_font(style);
+ if (font == NULL) {
+ DeleteObject(clipregion);
+ return false;
+ }
+ int wlen;
+ SIZE s;
+ LPWSTR wstring;
+ fontbak = (HFONT) SelectObject(plot_hdc, font);
+ GetTextExtentPoint(plot_hdc, text, length, &s);
+
+/*
+ RECT r;
+ r.left = x;
+ r.top = y - (3 * s.cy) / 4;
+ r.right = x + s.cx;
+ r.bottom = y + s.cy / 4;
+*/
+ SelectClipRgn(plot_hdc, clipregion);
+
+ SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT);
+ if ((style->background & 0xFF000000) != 0x01000000)
+ /* 100% alpha */
+ SetBkColor(plot_hdc, (DWORD) (style->background & 0x00FFFFFF));
+ SetBkMode(plot_hdc, TRANSPARENT);
+ SetTextColor(plot_hdc, (DWORD) (style->foreground & 0x00FFFFFF));
+
+ wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0);
+ wstring = malloc(2 * (wlen + 1));
+ if (wstring == NULL) {
+ return false;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen);
+ TextOutW(plot_hdc, x, y, wstring, wlen);
+
+ SelectClipRgn(plot_hdc, NULL);
+ free(wstring);
+ font = SelectObject(plot_hdc, fontbak);
+ DeleteObject(clipregion);
+ DeleteObject(font);
+
+ return true;
+}
+
+static bool disc(int x, int y, int radius, const plot_style_t *style)
+{
+ PLOT_LOG("disc at %d,%d radius %d", x, y, radius);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour)
+ & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return false;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return false;
+ }
+ HBRUSH brush = CreateSolidBrush(col);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return false;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return false;
+ }
+/*
+ RECT r;
+ r.left = x - radius;
+ r.top = y - radius;
+ r.right = x + radius;
+ r.bottom = y + radius;
+*/
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (style->fill_type == PLOT_OP_TYPE_NONE)
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x - radius, y - radius,
+ x - radius, y - radius);
+ else
+ Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius);
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return true;
+}
+
+static bool arc(int x, int y, int radius, int angle1, int angle2,
+ const plot_style_t *style)
+{
+ PLOT_LOG("arc centre %d,%d radius %d from %d to %d", x, y, radius,
+ angle1, angle2);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return false;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return false;
+ }
+
+ int q1, q2;
+ double a1=1.0, a2=1.0, b1=1.0, b2=1.0;
+ q1 = (int) ((angle1 + 45) / 90) - 45;
+ q2 = (int) ((angle2 + 45) / 90) - 45;
+ while (q1 > 4)
+ q1 -= 4;
+ while (q2 > 4)
+ q2 -= 4;
+ while (q1 <= 0)
+ q1 += 4;
+ while (q2 <= 0)
+ q2 += 4;
+ angle1 = ((angle1 + 45) % 90) - 45;
+ angle2 = ((angle2 + 45) % 90) - 45;
+
+ switch(q1) {
+ case 1:
+ a1 = 1.0;
+ b1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 2:
+ b1 = -1.0;
+ a1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 3:
+ a1 = -1.0;
+ b1 = tan((M_PI / 180) * angle1);
+ break;
+ case 4:
+ b1 = 1.0;
+ a1 = tan((M_PI / 180) * angle1);
+ break;
+ }
+
+ switch(q2) {
+ case 1:
+ a2 = 1.0;
+ b2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 2:
+ b2 = -1.0;
+ a2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 3:
+ a2 = -1.0;
+ b2 = tan((M_PI / 180) * angle2);
+ break;
+ case 4:
+ b2 = 1.0;
+ a2 = tan((M_PI / 180) * angle2);
+ break;
+ }
+
+/*
+ RECT r;
+ r.left = x - radius;
+ r.top = y - radius;
+ r.right = x + radius;
+ r.bottom = y + radius;
+*/
+ SelectClipRgn(plot_hdc, clipregion);
+
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x + (int)(a1 * radius), y + (int)(b1 * radius),
+ x + (int)(a2 * radius), y + (int)(b2 * radius));
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+
+ return true;
+}
+
+static bool
+plot_block(COLORREF col, int x, int y, int width, int height)
+{
+ HRGN clipregion;
+ HGDIOBJ original = NULL;
+
+ /* Bail early if we can */
+ if ((x >= plot_clip.right) ||
+ ((x + width) < plot_clip.left) ||
+ (y >= plot_clip.bottom) ||
+ ((y + height) < plot_clip.top)) {
+ /* Image completely outside clip region */
+ return true;
+ }
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ /* Saving the original pen object */
+ original = SelectObject(plot_hdc,GetStockObject(DC_PEN));
+
+ SelectObject(plot_hdc, GetStockObject(DC_PEN));
+ SelectObject(plot_hdc, GetStockObject(DC_BRUSH));
+ SetDCPenColor(plot_hdc, col);
+ SetDCBrushColor(plot_hdc, col);
+ Rectangle(plot_hdc, x, y, width, height);
+
+ SelectObject(plot_hdc,original); /* Restoring the original pen object */
+
+ DeleteObject(clipregion);
+
+ return true;
+
+}
+
+/* blunt force truma way of achiving alpha blended plotting */
+static bool
+plot_alpha_bitmap(HDC hdc,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width, int height)
+{
+#ifdef WINDOWS_GDI_ALPHA_WORKED
+ BLENDFUNCTION blnd = { AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA };
+ HDC bmihdc;
+ bool bltres;
+ bmihdc = CreateCompatibleDC(hdc);
+ SelectObject(bmihdc, bitmap->windib);
+ bltres = AlphaBlend(hdc,
+ x, y,
+ width, height,
+ bmihdc,
+ 0, 0,
+ bitmap->width, bitmap->height,
+ blnd);
+ DeleteDC(bmihdc);
+ return bltres;
+#else
+ HDC Memhdc;
+ BITMAPINFOHEADER bmih;
+ int v, vv, vi, h, hh, width4, transparency;
+ unsigned char alpha;
+ bool isscaled = false; /* set if the scaled bitmap requires freeing */
+ BITMAP MemBM;
+ BITMAPINFO *bmi;
+ HBITMAP MemBMh;
+
+ PLOT_LOG("%p bitmap %d,%d width %d height %d", bitmap, x, y, width, height);
+ PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom);
+
+ Memhdc = CreateCompatibleDC(hdc);
+ if (Memhdc == NULL) {
+ return false;
+ }
+
+ if ((bitmap->width != width) ||
+ (bitmap->height != height)) {
+ PLOT_LOG("scaling from %d,%d to %d,%d",
+ bitmap->width, bitmap->height, width, height);
+ bitmap = bitmap_scale(bitmap, width, height);
+ if (bitmap == NULL)
+ return false;
+ isscaled = true;
+ }
+
+ bmi = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER) +
+ (bitmap->width * bitmap->height * 4));
+ if (bmi == NULL) {
+ DeleteDC(Memhdc);
+ return false;
+ }
+
+ MemBMh = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height);
+ if (MemBMh == NULL){
+ free(bmi);
+ DeleteDC(Memhdc);
+ return false;
+ }
+
+ /* save 'background' data for alpha channel work */
+ SelectObject(Memhdc, MemBMh);
+ BitBlt(Memhdc, 0, 0, bitmap->width, bitmap->height, hdc, x, y, SRCCOPY);
+ GetObject(MemBMh, sizeof(BITMAP), &MemBM);
+
+ bmih.biSize = sizeof(bmih);
+ bmih.biWidth = bitmap->width;
+ bmih.biHeight = bitmap->height;
+ bmih.biPlanes = 1;
+ bmih.biBitCount = 32;
+ bmih.biCompression = BI_RGB;
+ bmih.biSizeImage = 4 * bitmap->height * bitmap->width;
+ bmih.biXPelsPerMeter = 3600; /* 100 dpi */
+ bmih.biYPelsPerMeter = 3600;
+ bmih.biClrUsed = 0;
+ bmih.biClrImportant = 0;
+ bmi->bmiHeader = bmih;
+
+ GetDIBits(hdc, MemBMh, 0, bitmap->height, bmi->bmiColors, bmi,
+ DIB_RGB_COLORS);
+
+ /* then load 'foreground' bits from bitmap->pixdata */
+
+ width4 = bitmap->width * 4;
+ for (v = 0, vv = 0, vi = (bitmap->height - 1) * width4;
+ v < bitmap->height;
+ v++, vv += bitmap->width, vi -= width4) {
+ for (h = 0, hh = 0; h < bitmap->width; h++, hh += 4) {
+ alpha = bitmap->pixdata[vi + hh + 3];
+/* multiplication of alpha value; subject to profiling could be optional */
+ if (alpha == 0xFF) {
+ bmi->bmiColors[vv + h].rgbBlue =
+ bitmap->pixdata[vi + hh + 2];
+ bmi->bmiColors[vv + h].rgbGreen =
+ bitmap->pixdata[vi + hh + 1];
+ bmi->bmiColors[vv + h].rgbRed =
+ bitmap->pixdata[vi + hh];
+ } else if (alpha > 0) {
+ transparency = 0x100 - alpha;
+ bmi->bmiColors[vv + h].rgbBlue =
+ (bmi->bmiColors[vv + h].rgbBlue
+ * transparency +
+ (bitmap->pixdata[vi + hh + 2]) *
+ alpha) >> 8;
+ bmi->bmiColors[vv + h].rgbGreen =
+ (bmi->bmiColors[vv + h].
+ rgbGreen
+ * transparency +
+ (bitmap->pixdata[vi + hh + 1]) *
+ alpha) >> 8;
+ bmi->bmiColors[vv + h].rgbRed =
+ (bmi->bmiColors[vv + h].rgbRed
+ * transparency +
+ bitmap->pixdata[vi + hh]
+ * alpha) >> 8;
+ }
+ }
+ }
+ SetDIBitsToDevice(hdc, x, y, bitmap->width, bitmap->height,
+ 0, 0, 0, bitmap->height,
+ (const void *) bmi->bmiColors,
+ bmi, DIB_RGB_COLORS);
+
+ if (isscaled && bitmap && bitmap->pixdata) {
+ free(bitmap->pixdata);
+ free(bitmap);
+ }
+
+ free(bmi);
+ DeleteObject(MemBMh);
+ DeleteDC(Memhdc);
+ return true;
+#endif
+}
+
+
+static bool
+plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
+{
+ int bltres;
+ HRGN clipregion;
+
+ /* Bail early if we can */
+ if ((x >= plot_clip.right) ||
+ ((x + width) < plot_clip.left) ||
+ (y >= plot_clip.bottom) ||
+ ((y + height) < plot_clip.top)) {
+ /* Image completely outside clip region */
+ return true;
+ }
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return false;
+ }
+
+ clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return false;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (bitmap->opaque) {
+ /* opaque bitmap */
+ if ((bitmap->width == width) &&
+ (bitmap->height == height)) {
+ /* unscaled */
+ bltres = SetDIBitsToDevice(plot_hdc,
+ x, y,
+ width, height,
+ 0, 0,
+ 0,
+ height,
+ bitmap->pixdata,
+ (BITMAPINFO *)bitmap->pbmi,
+ DIB_RGB_COLORS);
+ } else {
+ /* scaled */
+ SetStretchBltMode(plot_hdc, COLORONCOLOR);
+ bltres = StretchDIBits(plot_hdc,
+ x, y,
+ width, height,
+ 0, 0,
+ bitmap->width, bitmap->height,
+ bitmap->pixdata,
+ (BITMAPINFO *)bitmap->pbmi,
+ DIB_RGB_COLORS,
+ SRCCOPY);
+
+
+ }
+ } else {
+ /* Bitmap with alpha.*/
+ bltres = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height);
+ }
+
+ PLOT_LOG("bltres = %d", bltres);
+
+ DeleteObject(clipregion);
+
+ return true;
+
+}
+
+static bool
+windows_plot_bitmap(int x, int y,
+ int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags)
+{
+ int xf,yf;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+
+ /* Bail early if we can */
+
+ PLOT_LOG("Plotting %p at %d,%d by %d,%d",bitmap, x,y,width,height);
+
+ if (bitmap == NULL) {
+ LOG("Passed null bitmap!");
+ return true;
+ }
+
+ /* check if nothing to plot */
+ if (width == 0 || height == 0)
+ return true;
+
+ /* x and y define coordinate of top left of of the initial explicitly
+ * placed tile. The width and height are the image scaling and the
+ * bounding box defines the extent of the repeat (which may go in all
+ * four directions from the initial tile).
+ */
+
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just plot it */
+ if ((bitmap->width == 1) && (bitmap->height == 1)) {
+ if ((*(bitmap->pixdata + 3) & 0xff) == 0) {
+ return true;
+ }
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, x, y, x + width, y + height);
+
+ } else {
+ return plot_bitmap(bitmap, x, y, width, height);
+ }
+ }
+
+ /* Optimise tiled plots of 1x1 bitmaps by replacing with a flat fill
+ * of the area. Can only be done when image is fully opaque. */
+ if ((bitmap->width == 1) && (bitmap->height == 1)) {
+ if ((*(COLORREF *)bitmap->pixdata & 0xff000000) != 0) {
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
+ plot_clip.bottom);
+ }
+ }
+
+ /* Optimise tiled plots of bitmaps scaled to 1x1 by replacing with
+ * a flat fill of the area. Can only be done when image is fully
+ * opaque. */
+ if ((width == 1) && (height == 1)) {
+ if (bitmap->opaque) {
+ /** TODO: Currently using top left pixel. Maybe centre
+ * pixel or average value would be better. */
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
+ plot_clip.bottom);
+ }
+ }
+
+ PLOT_LOG("Tiled plotting %d,%d by %d,%d",x,y,width,height);
+ PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom);
+
+ /* get left most tile position */
+ if (repeat_x)
+ for (; x > plot_clip.left; x -= width);
+
+ /* get top most tile position */
+ if (repeat_y)
+ for (; y > plot_clip.top; y -= height);
+
+ PLOT_LOG("repeat from %d,%d to %ld,%ld", x, y, plot_clip.right, plot_clip.bottom);
+
+ /* tile down and across to extents */
+ for (xf = x; xf < plot_clip.right; xf += width) {
+ for (yf = y; yf < plot_clip.bottom; yf += height) {
+
+ plot_bitmap(bitmap, xf, yf, width, height);
+ if (!repeat_y)
+ break;
+ }
+ if (!repeat_x)
+ break;
+ }
+ return true;
+}
+
+
+static bool flush(void)
+{
+ PLOT_LOG("flush unimplemented");
+ return true;
+}
+
+static bool path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ PLOT_LOG("path unimplemented");
+ return true;
+}
+
+const struct plotter_table win_plotters = {
+ .rectangle = rectangle,
+ .line = line,
+ .polygon = polygon,
+ .clip = clip,
+ .text = text,
+ .disc = disc,
+ .arc = arc,
+ .bitmap = windows_plot_bitmap,
+ .flush = flush,
+ .path = path,
+ .option_knockout = true,
+};
diff --git a/frontends/windows/plot.h b/frontends/windows/plot.h
new file mode 100644
index 000000000..d69650d2a
--- /dev/null
+++ b/frontends/windows/plot.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include <windows.h>
+
+extern const struct plotter_table win_plotters;
+
+extern HDC plot_hdc;
+
diff --git a/frontends/windows/pointers.c b/frontends/windows/pointers.c
new file mode 100644
index 000000000..b5b74545d
--- /dev/null
+++ b/frontends/windows/pointers.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2015 Vincent Sanders <vince@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/>.
+ */
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <windows.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/corestrings.h"
+#include "utils/url.h"
+#include "utils/file.h"
+#include "desktop/browser.h"
+#include "desktop/gui_clipboard.h"
+
+#include "windows/schedule.h"
+#include "windows/window.h"
+#include "windows/filetype.h"
+#include "windows/pointers.h"
+
+struct nsws_pointers {
+ HCURSOR hand;
+ HCURSOR ibeam;
+ HCURSOR cross;
+ HCURSOR sizeall;
+ HCURSOR sizewe;
+ HCURSOR sizens;
+ HCURSOR sizenesw;
+ HCURSOR sizenwse;
+ HCURSOR wait;
+ HCURSOR appstarting;
+ HCURSOR no;
+ HCURSOR help;
+ HCURSOR arrow;
+};
+
+/** pre loaded pointer cursors */
+static struct nsws_pointers nsws_pointer;
+
+/* exported interface documented in windows/pointers.h */
+void nsws_window_init_pointers(HINSTANCE hinstance)
+{
+ nsws_pointer.hand = LoadCursor(NULL, IDC_HAND);
+ nsws_pointer.ibeam = LoadCursor(NULL, IDC_IBEAM);
+ nsws_pointer.cross = LoadCursor(NULL, IDC_CROSS);
+ nsws_pointer.sizeall = LoadCursor(NULL, IDC_SIZEALL);
+ nsws_pointer.sizewe = LoadCursor(NULL, IDC_SIZEWE);
+ nsws_pointer.sizens = LoadCursor(NULL, IDC_SIZENS);
+ nsws_pointer.sizenesw = LoadCursor(NULL, IDC_SIZENESW);
+ nsws_pointer.sizenwse = LoadCursor(NULL, IDC_SIZENWSE);
+ nsws_pointer.wait = LoadCursor(NULL, IDC_WAIT);
+ nsws_pointer.appstarting = LoadCursor(NULL, IDC_APPSTARTING);
+ nsws_pointer.no = LoadCursor(NULL, IDC_NO);
+ nsws_pointer.help = LoadCursor(NULL, IDC_HELP);
+ nsws_pointer.arrow = LoadCursor(NULL, IDC_ARROW);
+}
+
+/* exported interface documented in windows/pointers.h */
+HCURSOR nsws_get_pointer(gui_pointer_shape shape)
+{
+ switch (shape) {
+ case GUI_POINTER_POINT: /* link */
+ case GUI_POINTER_MENU:
+ return nsws_pointer.hand;
+
+ case GUI_POINTER_CARET: /* input */
+ return nsws_pointer.ibeam;
+
+ case GUI_POINTER_CROSS:
+ return nsws_pointer.cross;
+
+ case GUI_POINTER_MOVE:
+ return nsws_pointer.sizeall;
+
+ case GUI_POINTER_RIGHT:
+ case GUI_POINTER_LEFT:
+ return nsws_pointer.sizewe;
+
+ case GUI_POINTER_UP:
+ case GUI_POINTER_DOWN:
+ return nsws_pointer.sizens;
+
+ case GUI_POINTER_RU:
+ case GUI_POINTER_LD:
+ return nsws_pointer.sizenesw;
+
+ case GUI_POINTER_RD:
+ case GUI_POINTER_LU:
+ return nsws_pointer.sizenwse;
+
+ case GUI_POINTER_WAIT:
+ return nsws_pointer.wait;
+
+ case GUI_POINTER_PROGRESS:
+ return nsws_pointer.appstarting;
+
+ case GUI_POINTER_NO_DROP:
+ case GUI_POINTER_NOT_ALLOWED:
+ return nsws_pointer.no;
+
+ case GUI_POINTER_HELP:
+ return nsws_pointer.help;
+
+ default:
+ break;
+ }
+
+ return nsws_pointer.arrow;
+}
diff --git a/frontends/windows/pointers.h b/frontends/windows/pointers.h
new file mode 100644
index 000000000..cf91de993
--- /dev/null
+++ b/frontends/windows/pointers.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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
+ * Windows mouse cursor interface.
+ */
+
+#ifndef _NETSURF_WINDOWS_POINTERS_H_
+#define _NETSURF_WINDOWS_POINTERS_H_
+
+
+/**
+ * initialise the list of mouse cursors
+ */
+void nsws_window_init_pointers(HINSTANCE hinstance);
+
+/**
+ * get a win32 cursor handle for a pointer shape
+ */
+HCURSOR nsws_get_pointer(gui_pointer_shape shape);
+
+
+#endif
diff --git a/frontends/windows/prefs.c b/frontends/windows/prefs.c
new file mode 100644
index 000000000..adc0101a7
--- /dev/null
+++ b/frontends/windows/prefs.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#include "utils/config.h"
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "windows/gui.h"
+#include "windows/prefs.h"
+#include "windows/resourceid.h"
+#include "windows/windbg.h"
+
+#define NSWS_PREFS_WINDOW_WIDTH 600
+#define NSWS_PREFS_WINDOW_HEIGHT 400
+
+static CHOOSEFONT *nsws_prefs_font_prepare(int fontfamily, HWND parent)
+{
+ CHOOSEFONT *cf = malloc(sizeof(CHOOSEFONT));
+ if (cf == NULL) {
+ win32_warning(messages_get("NoMemory"),0);
+ return NULL;
+ }
+ LOGFONT *lf = malloc(sizeof(LOGFONT));
+ if (lf == NULL) {
+ win32_warning(messages_get("NoMemory"),0);
+ free(cf);
+ return NULL;
+ }
+ switch(fontfamily) {
+ case FF_ROMAN:
+ snprintf(lf->lfFaceName, LF_FACESIZE, "%s",
+ nsoption_charp(font_serif));
+ break;
+ case FF_MODERN:
+ snprintf(lf->lfFaceName, LF_FACESIZE, "%s",
+ nsoption_charp(font_mono));
+ break;
+ case FF_SCRIPT:
+ snprintf(lf->lfFaceName, LF_FACESIZE, "%s",
+ nsoption_charp(font_cursive));
+ break;
+ case FF_DECORATIVE:
+ snprintf(lf->lfFaceName, LF_FACESIZE, "%s",
+ nsoption_charp(font_fantasy));
+ break;
+ case FF_SWISS:
+ default:
+ snprintf(lf->lfFaceName, LF_FACESIZE, "%s",
+ nsoption_charp(font_sans));
+ break;
+ }
+
+ cf->lStructSize = sizeof(CHOOSEFONT);
+ cf->hwndOwner = parent;
+ cf->lpLogFont = lf;
+ cf->Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_LIMITSIZE;
+ cf->nSizeMin = 16;
+ cf->nSizeMax = 24;
+
+ return cf;
+}
+
+static void change_spinner(HWND sub, double change, double minval, double maxval)
+{
+ char *temp, number[6];
+ int len;
+ double value = 0;
+
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+
+ if (temp == NULL)
+ return;
+
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1), (LPARAM) temp);
+
+ value = strtod(temp, NULL) - change;
+
+ free(temp);
+ value = max(value, minval);
+ value = min(value, maxval);
+
+ if ((change == 1.0) || (change == -1.0))
+ snprintf(number, 6, "%.0f", value);
+ else
+ snprintf(number, 6, "%.1f", value);
+
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+}
+
+
+static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
+ UINT msg, WPARAM wparam, LPARAM lParam)
+{
+ int len;
+ char *temp, number[6];
+ HWND sub;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lParam);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONTDEF);
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Sans serif");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Serif");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Monospace");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Cursive");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Fantasy");
+ SendMessage(sub, CB_SETCURSEL,
+ (WPARAM) (nsoption_int(font_default) - 1), 0);
+
+ if ((nsoption_charp(font_sans) != NULL) &&
+ (nsoption_charp(font_sans)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_SANS);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_sans));
+ }
+ if ((nsoption_charp(font_serif) != NULL) &&
+ (nsoption_charp(font_serif)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_SERIF);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_serif));
+ }
+ if ((nsoption_charp(font_mono) != NULL) &&
+ (nsoption_charp(font_mono)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_MONO);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_mono));
+ }
+ if ((nsoption_charp(font_cursive) != NULL) &&
+ (nsoption_charp(font_cursive)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_CURSIVE);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_cursive));
+ }
+ if ((nsoption_charp(font_fantasy) != NULL) &&
+ (nsoption_charp(font_fantasy)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FANTASY);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_fantasy));
+ }
+ if (nsoption_int(font_min_size) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONT_MINSIZE);
+ snprintf(number, 6, "%.1f", nsoption_int(font_min_size) / 10.0);
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+ if (nsoption_int(font_size) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONT_SIZE);
+ snprintf(number, 6, "%.1f", nsoption_int(font_size) / 10.0);
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+ if (nsoption_int(max_fetchers) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCHERS);
+ snprintf(number, 6, "%d", nsoption_int(max_fetchers));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+ if (nsoption_int(max_fetchers_per_host) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HOST);
+ snprintf(number, 6, "%d",
+ nsoption_int(max_fetchers_per_host));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+ if (nsoption_int(max_cached_fetch_handles) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HANDLES);
+ snprintf(number, 6, "%d",
+ nsoption_int(max_cached_fetch_handles));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+
+
+ /* animation */
+ sub = GetDlgItem(hwnd, IDC_PREFS_NOANIMATION);
+ SendMessage(sub, BM_SETCHECK, (WPARAM)((nsoption_bool(animate_images))
+ ? BST_UNCHECKED : BST_CHECKED), 0);
+
+ if (nsoption_int(minimum_gif_delay) != 0) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_ANIMATIONDELAY);
+ snprintf(number, 6, "%.1f", nsoption_int(minimum_gif_delay) /
+ 100.0);
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((NMHDR FAR *)lParam)->code) {
+ case PSN_APPLY:
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONT_SIZE);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)
+ (len + 1), (LPARAM) temp);
+ nsoption_int(font_size) = (int)
+ (10 * strtod(temp, NULL));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONT_MINSIZE);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)
+ (len + 1), (LPARAM) temp);
+ nsoption_set_int(font_min_size,
+ (int)(10 * strtod(temp, NULL)));
+ free(temp);
+ }
+
+ /* animation */
+ nsoption_set_bool(animate_images,
+ (IsDlgButtonChecked(hwnd, IDC_PREFS_NOANIMATION) == BST_CHECKED) ? true : false);
+
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_ANIMATIONDELAY);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)
+ (len + 1), (LPARAM) temp);
+ nsoption_set_int(minimum_gif_delay,
+ (int)(100 * strtod(temp, NULL)));
+ free(temp);
+ }
+
+ break;
+
+ case UDN_DELTAPOS: {
+ NMUPDOWN *ud = (NMUPDOWN *)lParam;
+ switch(((NMHDR *)lParam)->idFrom) {
+ case IDC_PREFS_FONT_SIZE_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_FONT_SIZE), 0.1 * ud->iDelta, 1.0, 50.0);
+ return TRUE;
+
+ case IDC_PREFS_FONT_MINSIZE_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_FONT_MINSIZE), 0.1 * ud->iDelta, 1.0, 50.0);
+ return TRUE;
+
+ case IDC_PREFS_ANIMATIONDELAY_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_ANIMATIONDELAY), 0.1 * ud->iDelta, 0.1, 100.0);
+ return TRUE;
+
+ }
+ }
+ break;
+ }
+
+
+ case WM_COMMAND:
+ LOG("WM_COMMAND Identifier 0x%x",LOWORD(wparam));
+
+ switch(LOWORD(wparam)) {
+ case IDC_PREFS_PROXYTYPE:
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYTYPE);
+ nsoption_set_int(http_proxy_auth,
+ SendMessage(sub, CB_GETCURSEL, 0, 0) - 1);
+ nsoption_set_bool(http_proxy,
+ (nsoption_int(http_proxy_auth) != -1));
+ nsoption_set_int(http_proxy_auth,
+ nsoption_int(http_proxy_auth) +
+ (nsoption_bool(http_proxy)) ? 0 : 1);
+ break;
+
+ case IDC_PREFS_SANS: {
+ CHOOSEFONT *cf = nsws_prefs_font_prepare(FF_SWISS, hwnd);
+ if (cf == NULL) {
+ break;
+ }
+
+ if (ChooseFont(cf) == TRUE) {
+ nsoption_set_charp(font_sans,
+ strdup(cf->lpLogFont->lfFaceName));
+ }
+
+ free(cf->lpLogFont);
+ free(cf);
+ if ((nsoption_charp(font_sans) != NULL) &&
+ (nsoption_charp(font_sans)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_SANS);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_sans));
+ }
+ break;
+ }
+
+ case IDC_PREFS_SERIF: {
+ CHOOSEFONT *cf = nsws_prefs_font_prepare(FF_ROMAN, hwnd);
+ if (cf == NULL) {
+ break;
+ }
+
+ if (ChooseFont(cf) == TRUE) {
+ nsoption_set_charp(font_serif,
+ strdup(cf->lpLogFont->lfFaceName));
+ }
+
+ free(cf->lpLogFont);
+ free(cf);
+ if ((nsoption_charp(font_serif) != NULL) &&
+ (nsoption_charp(font_serif)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_SERIF);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_serif));
+ }
+ break;
+ }
+
+ case IDC_PREFS_MONO: {
+ CHOOSEFONT *cf = nsws_prefs_font_prepare(FF_MODERN, hwnd);
+ if (cf == NULL) {
+ break;
+ }
+
+ if (ChooseFont(cf) == TRUE) {
+ nsoption_set_charp(font_mono,
+ strdup(cf->lpLogFont->lfFaceName));
+ }
+
+ free(cf->lpLogFont);
+ free(cf);
+
+ if ((nsoption_charp(font_mono) != NULL) &&
+ (nsoption_charp(font_mono)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_MONO);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_mono));
+ }
+ break;
+ }
+
+ case IDC_PREFS_CURSIVE: {
+ CHOOSEFONT *cf = nsws_prefs_font_prepare(FF_SCRIPT, hwnd);
+ if (cf == NULL) {
+ break;
+ }
+
+ if (ChooseFont(cf) == TRUE) {
+ nsoption_set_charp(font_cursive,
+ strdup(cf->lpLogFont->lfFaceName));
+ }
+ free(cf->lpLogFont);
+ free(cf);
+ if ((nsoption_charp(font_cursive) != NULL) &&
+ (nsoption_charp(font_cursive)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_CURSIVE);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_cursive));
+ }
+ break;
+ }
+
+ case IDC_PREFS_FANTASY: {
+ CHOOSEFONT *cf = nsws_prefs_font_prepare(FF_DECORATIVE, hwnd);
+ if (cf == NULL) {
+ break;
+ }
+
+ if (ChooseFont(cf) == TRUE) {
+ nsoption_set_charp(font_fantasy,
+ strdup(cf->lpLogFont->lfFaceName));
+ }
+ free(cf->lpLogFont);
+ free(cf);
+ if ((nsoption_charp(font_fantasy) != NULL) &&
+ (nsoption_charp(font_fantasy)[0] != '\0')) {
+ sub = GetDlgItem(hwnd, IDC_PREFS_FANTASY);
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(font_fantasy));
+ }
+ break;
+ }
+
+ case IDC_PREFS_FONTDEF:
+ sub = GetDlgItem(hwnd, IDC_PREFS_FONTDEF);
+ nsoption_set_int(font_default,
+ SendMessage(sub, CB_GETCURSEL, 0, 0) + 1);
+ break;
+
+ }
+ break;
+
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK options_connections_dialog_handler(HWND hwnd,
+ UINT msg, WPARAM wparam, LPARAM lParam)
+{
+ int len;
+ char *temp, number[6];
+ HWND sub;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lParam);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYTYPE);
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"None");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Simple");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"Basic Auth");
+ SendMessage(sub, CB_ADDSTRING, 0, (LPARAM)"NTLM Auth");
+ if (nsoption_bool(http_proxy)) {
+ SendMessage(sub, CB_SETCURSEL, (WPARAM)
+ (nsoption_int(http_proxy_auth) + 1), 0);
+ } else {
+ SendMessage(sub, CB_SETCURSEL, 0, 0);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYHOST);
+ if ((nsoption_charp(http_proxy_host) != NULL) &&
+ (nsoption_charp(http_proxy_host)[0] != '\0'))
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(http_proxy_host));
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYPORT);
+ if (nsoption_int(http_proxy_port) != 0) {
+ snprintf(number, 6, "%d", nsoption_int(http_proxy_port));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYNAME);
+ if ((nsoption_charp(http_proxy_auth_user) != NULL) &&
+ (nsoption_charp(http_proxy_auth_user)[0] != '\0'))
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(http_proxy_auth_user));
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYPASS);
+ if ((nsoption_charp(http_proxy_auth_pass) != NULL) &&
+ (nsoption_charp(http_proxy_auth_pass)[0] != '\0'))
+ SendMessage(sub, WM_SETTEXT, 0,
+ (LPARAM)nsoption_charp(http_proxy_auth_pass));
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCHERS);
+ snprintf(number, 6, "%d", nsoption_int(max_fetchers));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HOST);
+ snprintf(number, 6, "%d", nsoption_int(max_fetchers_per_host));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HANDLES);
+ snprintf(number, 6, "%d", nsoption_int(max_cached_fetch_handles));
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
+
+ break;
+
+ case WM_NOTIFY:
+ switch (((NMHDR FAR *)lParam)->code) {
+ case PSN_APPLY:
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYHOST);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_charp(http_proxy_host, strdup(temp));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYPORT);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_int(http_proxy_port, atoi(temp));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYNAME);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_charp(http_proxy_auth_user, strdup(temp));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_PROXYPASS);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_charp(http_proxy_auth_pass, strdup(temp));
+ free(temp);
+ }
+
+ /* fetchers */
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCHERS);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_int(max_fetchers, atoi(temp));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HOST);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_int(max_fetchers_per_host, atoi(temp));
+ free(temp);
+ }
+
+ sub = GetDlgItem(hwnd, IDC_PREFS_FETCH_HANDLES);
+ len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
+ temp = malloc(len + 1);
+ if (temp != NULL) {
+ SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1),
+ (LPARAM)temp);
+ nsoption_set_int(max_cached_fetch_handles, atoi(temp));
+ free(temp);
+ }
+ break;
+
+ case UDN_DELTAPOS: {
+ NMUPDOWN *ud = (NMUPDOWN *)lParam;
+ switch(((NMHDR *)lParam)->idFrom) {
+ case IDC_PREFS_FETCHERS_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_FETCHERS), 1.0 * ud->iDelta, 1.0, 100.0);
+ return TRUE;
+
+ case IDC_PREFS_FETCH_HOST_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_FETCH_HOST), 1.0 * ud->iDelta, 1.0, 100.0);
+ return TRUE;
+
+ case IDC_PREFS_FETCH_HANDLES_SPIN:
+ change_spinner(GetDlgItem(hwnd, IDC_PREFS_FETCH_HANDLES), 1.0 * ud->iDelta, 1.0, 100.0);
+ return TRUE;
+
+ }
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
+ UINT msg, WPARAM wparam, LPARAM lParam)
+{
+ HWND sub;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lParam);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ /* homepage url */
+ sub = GetDlgItem(hwnd, IDC_PREFS_HOMEPAGE);
+ SendMessage(sub, WM_SETTEXT, 0, (LPARAM)nsoption_charp(homepage_url));
+
+ /* Display images */
+ sub = GetDlgItem(hwnd, IDC_PREFS_IMAGES);
+ SendMessage(sub, BM_SETCHECK,
+ (WPARAM) ((nsoption_bool(suppress_images)) ?
+ BST_CHECKED : BST_UNCHECKED), 0);
+
+ /* advert blocking */
+ sub = GetDlgItem(hwnd, IDC_PREFS_ADVERTS);
+ SendMessage(sub, BM_SETCHECK,
+ (WPARAM) ((nsoption_bool(block_advertisements)) ?
+ BST_CHECKED : BST_UNCHECKED), 0);
+
+ /* Referrer sending */
+ sub = GetDlgItem(hwnd, IDC_PREFS_REFERER);
+ SendMessage(sub, BM_SETCHECK,
+ (WPARAM)((nsoption_bool(send_referer)) ?
+ BST_CHECKED : BST_UNCHECKED), 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((NMHDR FAR *)lParam)->code) {
+ case PSN_APPLY:
+ /* homepage */
+ sub = GetDlgItem(hwnd, IDC_PREFS_HOMEPAGE);
+ if (sub != NULL) {
+ int text_length;
+ char *text;
+ text_length = SendMessage(sub,
+ WM_GETTEXTLENGTH, 0, 0);
+ text = malloc(text_length + 1);
+ if (text != NULL) {
+ SendMessage(sub, WM_GETTEXT,
+ (WPARAM)text_length + 1,
+ (LPARAM)text);
+ nsoption_set_charp(homepage_url, text);
+ }
+ }
+
+ nsoption_set_bool(suppress_images,
+ (IsDlgButtonChecked(hwnd, IDC_PREFS_IMAGES) == BST_CHECKED) ? true : false);
+
+ nsoption_set_bool(block_advertisements, (IsDlgButtonChecked(hwnd,
+ IDC_PREFS_ADVERTS) == BST_CHECKED) ? true : false);
+
+ nsoption_set_bool(send_referer, (IsDlgButtonChecked(hwnd,
+ IDC_PREFS_REFERER) == BST_CHECKED) ? true : false);
+
+ break;
+
+ }
+ }
+ return FALSE;
+}
+
+void nsws_prefs_dialog_init(HINSTANCE hinst, HWND parent)
+{
+ int ret;
+ PROPSHEETPAGE psp[3];
+ PROPSHEETHEADER psh;
+
+ psp[0].dwSize = sizeof(PROPSHEETPAGE);
+ psp[0].dwFlags = 0;/*PSP_USEICONID*/
+ psp[0].hInstance = hinst;
+ psp[0].pszTemplate = MAKEINTRESOURCE(IDD_DLG_OPTIONS_GENERAL);
+ psp[0].pfnDlgProc = options_general_dialog_handler;
+ psp[0].lParam = 0;
+ psp[0].pfnCallback = NULL;
+
+ psp[1].dwSize = sizeof(PROPSHEETPAGE);
+ psp[1].dwFlags = 0;/*PSP_USEICONID*/
+ psp[1].hInstance = hinst;
+ psp[1].pszTemplate = MAKEINTRESOURCE(IDD_DLG_OPTIONS_CONNECTIONS);
+ psp[1].pfnDlgProc = options_connections_dialog_handler;
+ psp[1].lParam = 0;
+ psp[1].pfnCallback = NULL;
+
+ psp[2].dwSize = sizeof(PROPSHEETPAGE);
+ psp[2].dwFlags = 0;/*PSP_USEICONID*/
+ psp[2].hInstance = hinst;
+ psp[2].pszTemplate = MAKEINTRESOURCE(IDD_DLG_OPTIONS_APPERANCE);
+ psp[2].pfnDlgProc = options_appearance_dialog_handler;
+ psp[2].lParam = 0;
+ psp[2].pfnCallback = NULL;
+
+
+ psh.dwSize = sizeof(PROPSHEETHEADER);
+ psh.dwFlags = PSH_NOAPPLYNOW | PSH_USEICONID | PSH_PROPSHEETPAGE;
+ psh.hwndParent = parent;
+ psh.hInstance = hinst;
+ psh.pszIcon = MAKEINTRESOURCE(IDR_NETSURF_ICON);
+ psh.pszCaption = (LPSTR) "NetSurf Options";
+ psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
+ psh.nStartPage = 0;
+ psh.ppsp = (LPCPROPSHEETPAGE) &psp;
+ psh.pfnCallback = NULL;
+
+ ret = PropertySheet(&psh);
+ if (ret == -1) {
+ win_perror("PropertySheet");
+ } else if (ret > 0) {
+ /* user saved changes */
+ nsoption_write(options_file_location, NULL, NULL);
+ }
+}
diff --git a/frontends/windows/prefs.h b/frontends/windows/prefs.h
new file mode 100644
index 000000000..dec004b60
--- /dev/null
+++ b/frontends/windows/prefs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_PREFS_H_
+#define _NETSURF_WINDOWS_PREFS_H_
+
+void nsws_prefs_dialog_init(HINSTANCE hinst, HWND parent);
+
+#endif
diff --git a/frontends/windows/res/NetSurf.ico b/frontends/windows/res/NetSurf.ico
new file mode 100644
index 000000000..e0c3d01e6
--- /dev/null
+++ b/frontends/windows/res/NetSurf.ico
Binary files differ
diff --git a/frontends/windows/res/adblock.css b/frontends/windows/res/adblock.css
new file mode 120000
index 000000000..ff2485622
--- /dev/null
+++ b/frontends/windows/res/adblock.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
diff --git a/frontends/windows/res/banner.bmp b/frontends/windows/res/banner.bmp
new file mode 100644
index 000000000..49525f83d
--- /dev/null
+++ b/frontends/windows/res/banner.bmp
Binary files differ
diff --git a/frontends/windows/res/ca-bundle.crt b/frontends/windows/res/ca-bundle.crt
new file mode 120000
index 000000000..0b0e416ad
--- /dev/null
+++ b/frontends/windows/res/ca-bundle.crt
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
diff --git a/frontends/windows/res/credits.html b/frontends/windows/res/credits.html
new file mode 120000
index 000000000..1ba17392b
--- /dev/null
+++ b/frontends/windows/res/credits.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
diff --git a/frontends/windows/res/default.css b/frontends/windows/res/default.css
new file mode 120000
index 000000000..a8579eb7c
--- /dev/null
+++ b/frontends/windows/res/default.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
diff --git a/frontends/windows/res/home.bmp b/frontends/windows/res/home.bmp
new file mode 100644
index 000000000..1f595ff4c
--- /dev/null
+++ b/frontends/windows/res/home.bmp
Binary files differ
diff --git a/frontends/windows/res/icons/back.png b/frontends/windows/res/icons/back.png
new file mode 100644
index 000000000..f219fd807
--- /dev/null
+++ b/frontends/windows/res/icons/back.png
Binary files differ
diff --git a/frontends/windows/res/icons/back_g.png b/frontends/windows/res/icons/back_g.png
new file mode 100644
index 000000000..0796bbbbf
--- /dev/null
+++ b/frontends/windows/res/icons/back_g.png
Binary files differ
diff --git a/frontends/windows/res/icons/back_h.png b/frontends/windows/res/icons/back_h.png
new file mode 100644
index 000000000..35e31386a
--- /dev/null
+++ b/frontends/windows/res/icons/back_h.png
Binary files differ
diff --git a/frontends/windows/res/icons/forward.png b/frontends/windows/res/icons/forward.png
new file mode 100644
index 000000000..f20c0cdf5
--- /dev/null
+++ b/frontends/windows/res/icons/forward.png
Binary files differ
diff --git a/frontends/windows/res/icons/forward_g.png b/frontends/windows/res/icons/forward_g.png
new file mode 100644
index 000000000..d847543f3
--- /dev/null
+++ b/frontends/windows/res/icons/forward_g.png
Binary files differ
diff --git a/frontends/windows/res/icons/forward_h.png b/frontends/windows/res/icons/forward_h.png
new file mode 100644
index 000000000..90c0fe2c7
--- /dev/null
+++ b/frontends/windows/res/icons/forward_h.png
Binary files differ
diff --git a/frontends/windows/res/icons/home.png b/frontends/windows/res/icons/home.png
new file mode 100644
index 000000000..604796025
--- /dev/null
+++ b/frontends/windows/res/icons/home.png
Binary files differ
diff --git a/frontends/windows/res/icons/home_g.png b/frontends/windows/res/icons/home_g.png
new file mode 100644
index 000000000..a644b0b03
--- /dev/null
+++ b/frontends/windows/res/icons/home_g.png
Binary files differ
diff --git a/frontends/windows/res/icons/home_h.png b/frontends/windows/res/icons/home_h.png
new file mode 100644
index 000000000..2d6be5f34
--- /dev/null
+++ b/frontends/windows/res/icons/home_h.png
Binary files differ
diff --git a/frontends/windows/res/icons/reload.png b/frontends/windows/res/icons/reload.png
new file mode 100644
index 000000000..a81f650b0
--- /dev/null
+++ b/frontends/windows/res/icons/reload.png
Binary files differ
diff --git a/frontends/windows/res/icons/reload_g.png b/frontends/windows/res/icons/reload_g.png
new file mode 100644
index 000000000..5251f206c
--- /dev/null
+++ b/frontends/windows/res/icons/reload_g.png
Binary files differ
diff --git a/frontends/windows/res/icons/reload_h.png b/frontends/windows/res/icons/reload_h.png
new file mode 100644
index 000000000..76e554e49
--- /dev/null
+++ b/frontends/windows/res/icons/reload_h.png
Binary files differ
diff --git a/frontends/windows/res/icons/stop.png b/frontends/windows/res/icons/stop.png
new file mode 100644
index 000000000..df64c5747
--- /dev/null
+++ b/frontends/windows/res/icons/stop.png
Binary files differ
diff --git a/frontends/windows/res/icons/stop_g.png b/frontends/windows/res/icons/stop_g.png
new file mode 100644
index 000000000..a2efa9e3d
--- /dev/null
+++ b/frontends/windows/res/icons/stop_g.png
Binary files differ
diff --git a/frontends/windows/res/icons/stop_h.png b/frontends/windows/res/icons/stop_h.png
new file mode 100644
index 000000000..3c3377cdf
--- /dev/null
+++ b/frontends/windows/res/icons/stop_h.png
Binary files differ
diff --git a/frontends/windows/res/installer.nsi b/frontends/windows/res/installer.nsi
new file mode 100644
index 000000000..0c733db2e
--- /dev/null
+++ b/frontends/windows/res/installer.nsi
@@ -0,0 +1,141 @@
+# This installs NetSurf execuatables and resources, creates a start menu shortcut, builds an uninstaller, and
+# adds uninstall information to the registry for Add/Remove Programs
+
+# show up in a few places.
+# All the other settings can be tweaked by editing the !defines at the top of this script
+!define APPNAME "NetSurf"
+!define COMPANYNAME "NetSurf"
+!define DESCRIPTION "Web Browser"
+# These three must be integers
+!define VERSIONMAJOR 3
+!define VERSIONMINOR 6
+!define VERSIONBUILD 1
+# These will be displayed by the "Click here for support information" link in "Add/Remove Programs"
+# It is possible to use "mailto:" links in here to open the email client
+!define HELPURL "http://www.netsurf-browser.org/" # "Support Information" link
+!define UPDATEURL "http://www.netsurf-browser.org/" # "Product Updates" link
+!define ABOUTURL "http://www.netsurf-browser.org/" # "Publisher" link
+# This is the size (in kB) of all the files copied into "Program Files"
+!define INSTALLSIZE 9000
+
+RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on)
+
+InstallDir "$PROGRAMFILES\${COMPANYNAME}\${APPNAME}"
+
+# rtf or txt file - remember if it is txt, it must be in the DOS text format (\r\n)
+LicenseData "COPYING"
+# This will be in the installer/uninstaller's title bar
+Name "${COMPANYNAME} - ${APPNAME}"
+Icon "frontends\windows\res\NetSurf.ico"
+outFile "netsurf-installer.exe"
+BrandingText "${COMPANYNAME}"
+
+!include LogicLib.nsh
+
+# Just three pages - license agreement, install location, and installation
+page license
+page directory
+Page instfiles
+
+!macro VerifyUserIsAdmin
+UserInfo::GetAccountType
+pop $0
+${If} $0 != "admin" ;Require admin rights on NT4+
+ messageBox mb_iconstop "Administrator rights required!"
+ setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
+ quit
+${EndIf}
+!macroend
+
+function .onInit
+ setShellVarContext all
+ !insertmacro VerifyUserIsAdmin
+functionEnd
+
+section "install"
+ # Files for the install directory - to build the installer, these should be in the same directory as the install script (this file)
+ setOutPath $INSTDIR
+ # Files added here should be removed by the uninstaller (see section "uninstall")
+ file "NetSurf.exe"
+ file /oname=NetSurf.ico "frontends\windows\res\NetSurf.ico"
+ file /oname=default.css "frontends\windows\res\default.css"
+ file /oname=internal.css "frontends\windows\res\internal.css"
+ file /oname=adblock.css "frontends\windows\res\adblock.css"
+ file /oname=welcome.html "frontends\windows\res\welcome.html"
+ file /oname=credits.html "frontends\windows\res\credits.html"
+ file /oname=licence.html "frontends\windows\res\licence.html"
+ file /oname=netsurf.png "frontends\windows\res\netsurf.png"
+ file /oname=messages "build-Linux-windows\messages"
+ file /oname=ca-bundle.crt "frontends\windows\res\ca-bundle.crt"
+ # Add any other files for the install directory (license files, app data, etc) here
+
+ # Uninstaller - See function un.onInit and section "uninstall" for configuration
+ writeUninstaller "$INSTDIR\uninstall.exe"
+
+ # Start Menu
+ createDirectory "$SMPROGRAMS\${COMPANYNAME}"
+ createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" "$INSTDIR\NetSurf.exe" "" "$INSTDIR\NetSurf.ico"
+
+ # Registry information for add/remove programs
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${COMPANYNAME} - ${APPNAME} - ${DESCRIPTION}"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\NetSurf.ico$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "$\"${COMPANYNAME}$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "$\"${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}$\""
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR}
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR}
+ # There is no option for modifying or repairing the install
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoModify" 1
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1
+ # Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE}
+sectionEnd
+
+# Uninstaller
+
+function un.onInit
+ SetShellVarContext all
+
+ #Verify the uninstaller - last chance to back out
+ MessageBox MB_OKCANCEL "Permanantly remove ${APPNAME}?" IDOK next
+ Abort
+ next:
+ !insertmacro VerifyUserIsAdmin
+functionEnd
+
+section "uninstall"
+
+ # Remove Start Menu launcher
+ delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk"
+ # Try to remove the Start Menu folder - this will only happen if it is empty
+ rmDir "$SMPROGRAMS\${COMPANYNAME}"
+
+ # Remove files
+ delete $INSTDIR\NetSurf.exe
+ delete $INSTDIR\NetSurf.ico
+ delete $INSTDIR\libcares-2.dll
+ delete $INSTDIR\libgnurx-0.dll
+ delete $INSTDIR\default.css
+ delete $INSTDIR\internal.css
+ delete $INSTDIR\adblock.css
+ delete $INSTDIR\welcome.html
+ delete $INSTDIR\credits.html
+ delete $INSTDIR\licence.html
+ delete $INSTDIR\netsurf.png
+ delete $INSTDIR\messages
+ delete $INSTDIR\ca-bundle.crt
+
+ # Always delete uninstaller as the last action
+ delete $INSTDIR\uninstall.exe
+
+ # Try to remove the install directory - this will only happen if it is empty
+ rmDir $INSTDIR
+
+ # Remove uninstaller information from the registry
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}"
+sectionEnd
diff --git a/frontends/windows/res/internal.css b/frontends/windows/res/internal.css
new file mode 120000
index 000000000..17f9f1504
--- /dev/null
+++ b/frontends/windows/res/internal.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
diff --git a/frontends/windows/res/licence.html b/frontends/windows/res/licence.html
new file mode 120000
index 000000000..147dd6db2
--- /dev/null
+++ b/frontends/windows/res/licence.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
diff --git a/frontends/windows/res/netsurf.gif b/frontends/windows/res/netsurf.gif
new file mode 100644
index 000000000..f4ee3aa15
--- /dev/null
+++ b/frontends/windows/res/netsurf.gif
Binary files differ
diff --git a/frontends/windows/res/netsurf.png b/frontends/windows/res/netsurf.png
new file mode 120000
index 000000000..905512c25
--- /dev/null
+++ b/frontends/windows/res/netsurf.png
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
diff --git a/frontends/windows/res/quirks.css b/frontends/windows/res/quirks.css
new file mode 120000
index 000000000..88aabe48c
--- /dev/null
+++ b/frontends/windows/res/quirks.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/frontends/windows/res/resource.rc b/frontends/windows/res/resource.rc
new file mode 100644
index 000000000..b83205f6a
--- /dev/null
+++ b/frontends/windows/res/resource.rc
@@ -0,0 +1,265 @@
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+
+#include "../resourceid.h"
+
+
+IDR_NETSURF_ICON ICON DISCARDABLE "NetSurf.ico"
+IDR_TOOLBAR_BITMAP BITMAP DISCARDABLE "toolbar.bmp"
+IDR_TOOLBAR_BITMAP_GREY BITMAP DISCARDABLE "toolbarg.bmp"
+IDR_TOOLBAR_BITMAP_HOT BITMAP DISCARDABLE "toolbarh.bmp"
+IDR_NETSURF_BANNER BITMAP DISCARDABLE "banner.bmp"
+IDR_HOME_BITMAP BITMAP DISCARDABLE "home.bmp"
+
+IDR_THROBBER_FRAME0_BITMAP BITMAP DISCARDABLE "throbber/throbber0.bmp"
+IDR_THROBBER_FRAME1_BITMAP BITMAP DISCARDABLE "throbber/throbber1.bmp"
+IDR_THROBBER_FRAME2_BITMAP BITMAP DISCARDABLE "throbber/throbber2.bmp"
+IDR_THROBBER_FRAME3_BITMAP BITMAP DISCARDABLE "throbber/throbber3.bmp"
+IDR_THROBBER_FRAME4_BITMAP BITMAP DISCARDABLE "throbber/throbber4.bmp"
+IDR_THROBBER_FRAME5_BITMAP BITMAP DISCARDABLE "throbber/throbber5.bmp"
+IDR_THROBBER_FRAME6_BITMAP BITMAP DISCARDABLE "throbber/throbber6.bmp"
+IDR_THROBBER_FRAME7_BITMAP BITMAP DISCARDABLE "throbber/throbber7.bmp"
+
+IDR_MENU_MAIN MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New Window",IDM_FILE_OPEN_WINDOW
+ MENUITEM "Open &Location",IDM_FILE_OPEN_LOCATION
+ MENUITEM "&Close",IDM_FILE_CLOSE_WINDOW
+ MENUITEM SEPARATOR
+ MENUITEM "&Save Page",IDM_FILE_SAVE_PAGE,GRAYED,HELP
+ POPUP "Save Page &As"
+ BEGIN
+ MENUITEM "Text",IDM_FILE_SAVEAS_TEXT,GRAYED
+ MENUITEM "PDF",IDM_FILE_SAVEAS_PDF,GRAYED
+ MENUITEM "Postscript",IDM_FILE_SAVEAS_POSTSCRIPT,GRAYED
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Print Pre&view",IDM_FILE_PRINT_PREVIEW
+ MENUITEM "&Print",IDM_FILE_PRINT
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit",IDM_FILE_QUIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "Cu&t",IDM_EDIT_CUT
+ MENUITEM "&Copy",IDM_EDIT_COPY
+ MENUITEM "&Paste",IDM_EDIT_PASTE
+ MENUITEM "&Delete",IDM_EDIT_DELETE
+ MENUITEM SEPARATOR
+ MENUITEM "Select &All",IDM_EDIT_SELECT_ALL
+ MENUITEM SEPARATOR
+ MENUITEM "&Find",IDM_EDIT_SEARCH
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "Stop",IDM_NAV_STOP
+ MENUITEM "Reload",IDM_NAV_RELOAD
+ MENUITEM SEPARATOR
+ POPUP "&Zoom"
+ BEGIN
+ MENUITEM "Zoom &In",IDM_VIEW_ZOOMPLUS
+ MENUITEM "Zoom &Out",IDM_VIEW_ZOOMMINUS
+ MENUITEM "&Reset",IDM_VIEW_ZOOMNORMAL
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Page S&ource",IDM_VIEW_SOURCE
+ MENUITEM "&Full Screen",IDM_VIEW_FULLSCREEN
+ END
+ POPUP "&History"
+ BEGIN
+ MENUITEM "Back",IDM_NAV_BACK
+ MENUITEM "Forward",IDM_NAV_FORWARD
+ MENUITEM "Home",IDM_NAV_HOME
+ MENUITEM SEPARATOR
+ MENUITEM "Local History",IDM_NAV_LOCALHISTORY
+ MENUITEM "Global History",IDM_NAV_GLOBALHISTORY,GRAYED
+ END
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Downloads",IDM_VIEW_DOWNLOADS
+ MENUITEM "Save size and location",IDM_VIEW_SAVE_WIN_METRICS
+ POPUP "Debugging"
+ BEGIN
+ MENUITEM "Debug rendering",IDM_VIEW_TOGGLE_DEBUG_RENDERING
+ MENUITEM "Save Box Tree",IDM_VIEW_DEBUGGING_SAVE_BOXTREE,GRAYED
+ MENUITEM "Save DOM Tree",IDM_VIEW_DEBUGGING_SAVE_DOMTREE,GRAYED
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Options...",IDM_EDIT_PREFERENCES
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents",IDM_HELP_CONTENTS
+ MENUITEM "G&uide",IDM_HELP_GUIDE
+ MENUITEM "&Info",IDM_HELP_INFO
+ MENUITEM SEPARATOR
+ MENUITEM "&About NetSurf",IDM_HELP_ABOUT
+ END
+END
+
+IDR_MENU_CONTEXT MENU
+BEGIN
+ POPUP "Context"
+ BEGIN
+ MENUITEM "&Back",IDM_NAV_BACK
+ MENUITEM "F&orward",IDM_NAV_FORWARD
+ MENUITEM "&Home",IDM_NAV_HOME
+ MENUITEM "&Stop",IDM_NAV_STOP
+ MENUITEM "&Reload",IDM_NAV_RELOAD
+ MENUITEM SEPARATOR
+ MENUITEM "C&ut",IDM_EDIT_CUT,GRAYED
+ MENUITEM "&Copy",IDM_EDIT_COPY,GRAYED
+ MENUITEM "&Paste",IDM_EDIT_PASTE,GRAYED
+ MENUITEM "&Delete",IDM_EDIT_DELETE,GRAYED
+ END
+END
+
+IDD_DLG_ABOUT DIALOGEX 10,10,206,133
+CAPTION "About NetSurf"
+FONT 8,"MS Sans Serif",0,0,0
+STYLE WS_VISIBLE|WS_CAPTION|WS_SYSMENU
+EXSTYLE WS_EX_DLGMODALFRAME
+BEGIN
+ CONTROL IDR_NETSURF_BANNER,IDC_IMG1,"Static",SS_BITMAP|0x40L /*SS_REALSIZECONTROL*/,0,0,205,53
+ CONTROL "NetSurf",IDC_ABOUT_VERSION,"Static",SS_LEFT,10,60,185,16
+ CONTROL "NetSurf is a small fast browser",IDC_ABOUT_TEXT,"Static",SS_LEFT,10,83,185,8
+ CONTROL "Copyright 2003-2011 The NetSurf Developers",IDC_ABOUT_COPYRIGHT,"Static",SS_LEFT,10,96,185,8
+ CONTROL "&OK",IDOK,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,143,111,54,15
+ CONTROL "&Credits",IDC_BTN_CREDITS,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,10,111,54,15
+ CONTROL "&Licence",IDC_BTN_LICENCE,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,70,111,54,15
+END
+
+IDD_DLG_DOWNLOAD DIALOGEX 0,0,201,84
+CAPTION "Download"
+FONT 8,"MS Sans Serif",0,0,0
+STYLE WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_SETFONT
+EXSTYLE WS_EX_DLGMODALFRAME
+BEGIN
+ CONTROL "downloading [file] [size] from [domain] to [destination]",IDC_DOWNLOAD_LABEL,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_CENTER,6,6,189,35
+ CONTROL "progress",IDC_DOWNLOAD_PROGRESS,PROGRESS_CLASS,WS_VISIBLE,6,50,189,10
+ CONTROL "&OK",IDOK,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,141,66,54,15
+ CONTROL "&Cancel",IDCANCEL,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,81,66,54,15
+END
+
+
+IDD_DLG_OPTIONS_GENERAL DIALOGEX 0,0,220,200
+CAPTION "General"
+FONT 8,"MS Shell Dlg"
+STYLE DS_CONTROL|DS_SHELLFONT
+BEGIN
+ /* home page entry */
+ CONTROL "Home Page",IDC_STATIC,"Static",SS_LEFT,7,7,40,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,47,11,166,1
+ CONTROL IDR_HOME_BITMAP,IDC_STATIC,"Static",SS_BITMAP,15,19,24,24
+ CONTROL "",IDC_PREFS_HOMEPAGE,"Edit",WS_TABSTOP|ES_OEMCONVERT|ES_AUTOHSCROLL,43,19,170,14,WS_EX_CLIENTEDGE
+
+
+ /* Content control */
+ CONTROL "Content Control",IDC_STATIC,"Static",SS_LEFT,7,40,60,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,67,44,146,1
+
+ CONTROL "Hide Images",IDC_PREFS_IMAGES,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,43,52,67,10
+ CONTROL "Hide Advertisements",IDC_PREFS_ADVERTS,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,43,66,81,10
+ CONTROL "Send referer",IDC_PREFS_REFERER,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,43,80,55,10
+
+END
+
+IDD_DLG_OPTIONS_CONNECTIONS DIALOGEX 0,0,220,200
+CAPTION "Connections"
+FONT 8,"MS Shell Dlg"
+STYLE DS_CONTROL|DS_SHELLFONT
+BEGIN
+ /* proxy divider */
+ CONTROL "Proxy",IDC_STATIC,"Static",SS_LEFT,7,7,30,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,37,11,176,1
+
+ /* proxy controls */
+ CONTROL "Type:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,22,40,8
+ CONTROL "",IDC_PREFS_PROXYTYPE,"ComboBox",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST,80,19,60,60
+
+ CONTROL "Server:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,39,28,8
+ CONTROL "",IDC_PREFS_PROXYHOST,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|ES_OEMCONVERT|ES_AUTOHSCROLL,80,36,80,14,WS_EX_CLIENTEDGE
+
+ CONTROL "Port:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,164,39,16,8
+ CONTROL "",IDC_PREFS_PROXYPORT,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|ES_OEMCONVERT|ES_AUTOHSCROLL,182,36,24,14,WS_EX_CLIENTEDGE
+
+ CONTROL "Username:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,60,35,8
+ CONTROL "",IDC_PREFS_PROXYNAME,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|ES_OEMCONVERT|ES_AUTOHSCROLL,80,57,45,14,WS_EX_CLIENTEDGE
+
+ CONTROL "Password:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,132,60,34,8
+ CONTROL "",IDC_PREFS_PROXYPASS,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|ES_OEMCONVERT|ES_AUTOHSCROLL|ES_PASSWORD,168,57,45,14,WS_EX_CLIENTEDGE
+
+
+ /* fetcher divider */
+ CONTROL "Fetchers",IDC_STATIC,"Static",SS_LEFT,7,78,40,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,42,82,171,1
+
+ /* max fetchers */
+ CONTROL "Max Fetchers:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP,43,96,64,8
+ CONTROL "",IDC_PREFS_FETCHERS,"Edit",ES_NUMBER|ES_RIGHT|WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|WS_BORDER,111,93,30,14
+ CONTROL "Max Fetchers",IDC_PREFS_FETCHERS_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,341,122,11,15
+
+ /* fetchers per host */
+ CONTROL "Fetches per host:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP,43,118,64,8
+ CONTROL "",IDC_PREFS_FETCH_HOST,"Edit",ES_NUMBER|ES_RIGHT|WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|WS_BORDER,111,114,30,14
+ CONTROL "Fetches per host",IDC_PREFS_FETCH_HOST_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,341,140,11,15
+
+ /* cached fetchers */
+ CONTROL "Cached Fetches:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP,43,138,64,8
+ CONTROL "",IDC_PREFS_FETCH_HANDLES,"Edit",ES_NUMBER|ES_RIGHT|WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|WS_BORDER,111,135,30,14
+ CONTROL "Cached Fetches",IDC_PREFS_FETCH_HANDLES_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,341,158,11,15
+
+END
+
+IDD_DLG_OPTIONS_APPERANCE DIALOGEX 10,10,220,200
+CAPTION "Apperance"
+FONT 8,"MS Shell Dlg"
+STYLE DS_CONTROL|DS_SHELLFONT
+BEGIN
+ /* proxy separator */
+ CONTROL "Fonts",IDC_STATIC,"Static",SS_LEFT,7,7,20,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,27,11,186,1
+
+ /* font controls */
+ CONTROL "Sans-serif:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,22,44,8
+ CONTROL "Sans-serif",IDC_PREFS_SANS,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,89,19,50,14
+
+ CONTROL "Serif:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,40,24,8
+ CONTROL "Serif",IDC_PREFS_SERIF,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,89,37,50,14
+
+ CONTROL "Monospace:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,58,40,8
+ CONTROL "Monospace",IDC_PREFS_MONO,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,89,55,50,14
+
+ CONTROL "Cursive:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,76,32,8
+ CONTROL "Cursive",IDC_PREFS_CURSIVE,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,89,73,50,14
+
+ CONTROL "Fantasy:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,94,32,8
+ CONTROL "Fantasy",IDC_PREFS_FANTASY,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,89,91,50,14
+
+
+ CONTROL "Default:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,112,38,8
+ CONTROL "",IDC_PREFS_FONTDEF,"ComboBox",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST,89,109,50,60
+
+ CONTROL "Size:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,147,112,16,8
+ CONTROL "",IDC_PREFS_FONT_SIZE,"Edit",ES_NUMBER|WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,165,109,35,14,WS_EX_CLIENTEDGE
+ CONTROL "Font Size",IDC_PREFS_FONT_SIZE_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,75,137,11,15
+
+ CONTROL "Minimum Size:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,43,130,52,8
+ CONTROL "",IDC_PREFS_FONT_MINSIZE,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,97,127,35,14,WS_EX_CLIENTEDGE
+ CONTROL "Minimum Font Size",IDC_PREFS_FONT_MINSIZE_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,76,159,11,15
+
+ /* animation separator */
+ CONTROL "Animation",IDC_STATIC,"Static",SS_LEFT,7,148,36,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,43,152,170,1
+
+ CONTROL "Disable",IDC_PREFS_NOANIMATION,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,43,163,39,10
+ CONTROL "Minimum delay:",IDC_STATIC,"Static",WS_CHILDWINDOW|WS_VISIBLE|WS_GROUP|SS_LEFT,55,180,56,8
+ CONTROL "",IDC_PREFS_ANIMATIONDELAY,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,113,177,35,14,WS_EX_CLIENTEDGE
+ CONTROL "Min delay",IDC_PREFS_ANIMATIONDELAY_SPIN,UPDOWN_CLASS,UDS_AUTOBUDDY|UDS_ALIGNRIGHT|WS_VISIBLE,43,210,11,15
+
+
+
+END
diff --git a/frontends/windows/res/throbber.avi b/frontends/windows/res/throbber.avi
new file mode 100644
index 000000000..cced3a556
--- /dev/null
+++ b/frontends/windows/res/throbber.avi
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber0.bmp b/frontends/windows/res/throbber/throbber0.bmp
new file mode 100644
index 000000000..2cef4da70
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber0.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber0.png b/frontends/windows/res/throbber/throbber0.png
new file mode 100755
index 000000000..ad13c5408
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber0.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber1.bmp b/frontends/windows/res/throbber/throbber1.bmp
new file mode 100644
index 000000000..7c7feb6b2
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber1.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber1.png b/frontends/windows/res/throbber/throbber1.png
new file mode 100755
index 000000000..9e4e575a3
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber1.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber2.bmp b/frontends/windows/res/throbber/throbber2.bmp
new file mode 100644
index 000000000..7d1d1147a
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber2.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber2.png b/frontends/windows/res/throbber/throbber2.png
new file mode 100755
index 000000000..f571f7093
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber2.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber3.bmp b/frontends/windows/res/throbber/throbber3.bmp
new file mode 100644
index 000000000..1f98b12b0
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber3.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber3.png b/frontends/windows/res/throbber/throbber3.png
new file mode 100755
index 000000000..0bc8b66b5
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber3.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber4.bmp b/frontends/windows/res/throbber/throbber4.bmp
new file mode 100644
index 000000000..a5ddc00e3
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber4.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber4.png b/frontends/windows/res/throbber/throbber4.png
new file mode 100755
index 000000000..37c9ce842
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber4.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber5.bmp b/frontends/windows/res/throbber/throbber5.bmp
new file mode 100644
index 000000000..261f8cd13
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber5.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber5.png b/frontends/windows/res/throbber/throbber5.png
new file mode 100755
index 000000000..54f83d224
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber5.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber6.bmp b/frontends/windows/res/throbber/throbber6.bmp
new file mode 100644
index 000000000..01d3f480d
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber6.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber6.png b/frontends/windows/res/throbber/throbber6.png
new file mode 100755
index 000000000..e36e1f872
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber6.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber7.bmp b/frontends/windows/res/throbber/throbber7.bmp
new file mode 100644
index 000000000..b5421cf0e
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber7.bmp
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber7.png b/frontends/windows/res/throbber/throbber7.png
new file mode 100755
index 000000000..c6f2628b5
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber7.png
Binary files differ
diff --git a/frontends/windows/res/throbber/throbber8.png b/frontends/windows/res/throbber/throbber8.png
new file mode 100755
index 000000000..d29d94414
--- /dev/null
+++ b/frontends/windows/res/throbber/throbber8.png
Binary files differ
diff --git a/frontends/windows/res/toolbar.bmp b/frontends/windows/res/toolbar.bmp
new file mode 100644
index 000000000..4087878a6
--- /dev/null
+++ b/frontends/windows/res/toolbar.bmp
Binary files differ
diff --git a/frontends/windows/res/toolbarg.bmp b/frontends/windows/res/toolbarg.bmp
new file mode 100644
index 000000000..9a59e8d43
--- /dev/null
+++ b/frontends/windows/res/toolbarg.bmp
Binary files differ
diff --git a/frontends/windows/res/toolbarh.bmp b/frontends/windows/res/toolbarh.bmp
new file mode 100644
index 000000000..81e666f03
--- /dev/null
+++ b/frontends/windows/res/toolbarh.bmp
Binary files differ
diff --git a/frontends/windows/res/welcome.html b/frontends/windows/res/welcome.html
new file mode 120000
index 000000000..28362130a
--- /dev/null
+++ b/frontends/windows/res/welcome.html
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
diff --git a/frontends/windows/resourceid.h b/frontends/windows/resourceid.h
new file mode 100644
index 000000000..bdec80a30
--- /dev/null
+++ b/frontends/windows/resourceid.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_RESOURCEID_H_
+#define _NETSURF_WINDOWS_RESOURCEID_H_
+
+#ifndef IDC_STATIC
+#define IDC_STATIC (-1)
+#endif
+
+#define IDR_NETSURF_ICON 100
+#define IDR_TOOLBAR_BITMAP 102
+#define IDR_TOOLBAR_BITMAP_GREY 103
+#define IDR_TOOLBAR_BITMAP_HOT 104
+#define IDR_NETSURF_BANNER 105
+#define IDR_HOME_BITMAP 114
+
+#define IDR_THROBBER_FRAME0_BITMAP 106
+#define IDR_THROBBER_FRAME1_BITMAP 107
+#define IDR_THROBBER_FRAME2_BITMAP 108
+#define IDR_THROBBER_FRAME3_BITMAP 109
+#define IDR_THROBBER_FRAME4_BITMAP 110
+#define IDR_THROBBER_FRAME5_BITMAP 111
+#define IDR_THROBBER_FRAME6_BITMAP 112
+#define IDR_THROBBER_FRAME7_BITMAP 113
+
+#define IDD_DLG_ABOUT 1000
+#define IDC_IMG1 1001
+#define IDC_ABOUT_VERSION 1002
+#define IDC_ABOUT_TEXT 1003
+#define IDC_ABOUT_COPYRIGHT 1004
+#define IDC_BTN_CREDITS 1005
+#define IDC_BTN_LICENCE 1006
+
+#define IDD_DLG_DOWNLOAD 1100
+#define IDC_DOWNLOAD_LABEL 1101
+#define IDC_DOWNLOAD_PROGRESS 1102
+
+#define IDD_DLG_MAIN 1300
+#define IDC_MAIN_TOOLBAR 1301
+#define IDC_MAIN_URLBAR 1302
+#define IDC_MAIN_THROBBER 1303
+#define IDC_MAIN_DRAWINGAREA 1304
+#define IDC_MAIN_STATUSBAR 1305
+#define IDC_MAIN_LAUNCH_URL 1306
+
+#define IDD_DLG_OPTIONS_GENERAL 1400
+#define IDC_PREFS_HOMEPAGE 1401
+#define IDC_PREFS_IMAGES 1402
+#define IDC_PREFS_ADVERTS 1403
+#define IDC_PREFS_REFERER 1404
+
+#define IDD_DLG_OPTIONS_CONNECTIONS 1500
+#define IDC_PREFS_FETCHERS 1501
+#define IDC_PREFS_FETCHERS_SPIN 1502
+#define IDC_PREFS_FETCH_HOST 1503
+#define IDC_PREFS_FETCH_HOST_SPIN 1504
+#define IDC_PREFS_FETCH_HANDLES 1505
+#define IDC_PREFS_FETCH_HANDLES_SPIN 1506
+
+#define IDD_DLG_OPTIONS_APPERANCE 1200
+#define IDC_PREFS_PROXYTYPE 1206
+#define IDC_PREFS_PROXYHOST 1207
+#define IDC_PREFS_PROXYPORT 1208
+#define IDC_PREFS_PROXYNAME 1209
+#define IDC_PREFS_PROXYPASS 1210
+#define IDC_PREFS_FONT_SIZE 1211
+#define IDC_PREFS_FONT_MINSIZE 1212
+#define IDC_PREFS_FONT_MINSIZE_SPIN 1213
+#define IDC_PREFS_SANS 1214
+#define IDC_PREFS_SERIF 1215
+#define IDC_PREFS_FONT_SIZE_SPIN 1216
+#define IDC_PREFS_MONO 1217
+#define IDC_PREFS_CURSIVE 1218
+#define IDC_PREFS_FANTASY 1219
+#define IDC_PREFS_FONTDEF 1220
+#define IDC_PREFS_NOANIMATION 1227
+#define IDC_PREFS_ANIMATIONDELAY 1228
+#define IDC_PREFS_ANIMATIONDELAY_SPIN 1229
+
+#define IDR_MENU_MAIN 10000
+#define IDM_FILE_OPEN_WINDOW 10001
+#define IDM_FILE_OPEN_LOCATION 10002
+#define IDM_FILE_CLOSE_WINDOW 10003
+#define IDM_FILE_SAVE_PAGE 10004
+#define IDM_FILE_SAVEAS_TEXT 10005
+#define IDM_FILE_SAVEAS_PDF 10006
+#define IDM_FILE_SAVEAS_POSTSCRIPT 10007
+#define IDM_FILE_PRINT_PREVIEW 10008
+#define IDM_FILE_PRINT 10009
+#define IDM_FILE_QUIT 10010
+#define IDM_EDIT_CUT 10011
+#define IDM_EDIT_COPY 10012
+#define IDM_EDIT_PASTE 10013
+#define IDM_EDIT_DELETE 10014
+#define IDM_EDIT_SELECT_ALL 10015
+#define IDM_EDIT_SEARCH 10016
+#define IDM_NAV_STOP 10017
+#define IDM_NAV_RELOAD 10018
+#define IDM_VIEW_ZOOMPLUS 10019
+#define IDM_VIEW_ZOOMMINUS 10020
+#define IDM_VIEW_ZOOMNORMAL 10021
+#define IDM_VIEW_SOURCE 10022
+#define IDM_VIEW_FULLSCREEN 10023
+#define IDM_NAV_BACK 10024
+#define IDM_NAV_FORWARD 10025
+#define IDM_NAV_HOME 10026
+#define IDM_NAV_LOCALHISTORY 10027
+#define IDM_NAV_GLOBALHISTORY 10028
+#define IDM_VIEW_DOWNLOADS 10029
+#define IDM_VIEW_SAVE_WIN_METRICS 10030
+#define IDM_VIEW_TOGGLE_DEBUG_RENDERING 10031
+#define IDM_VIEW_DEBUGGING_SAVE_BOXTREE 10032
+#define IDM_VIEW_DEBUGGING_SAVE_DOMTREE 10033
+#define IDM_EDIT_PREFERENCES 10034
+#define IDM_HELP_CONTENTS 10035
+#define IDM_HELP_GUIDE 10036
+#define IDM_HELP_INFO 10037
+#define IDM_HELP_ABOUT 10038
+
+#define IDR_MENU_CONTEXT 11000
+
+#endif
diff --git a/frontends/windows/schedule.c b/frontends/windows/schedule.c
new file mode 100644
index 000000000..5366add9c
--- /dev/null
+++ b/frontends/windows/schedule.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <time.h>
+
+#include "utils/sys_time.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/errors.h"
+
+#include "windows/schedule.h"
+
+#ifdef DEBUG_SCHEDULER
+#define SRLOG(x...) LOG(x)
+#else
+#define SRLOG(x...) ((void) 0)
+#endif
+
+/* linked list of scheduled callbacks */
+static struct nscallback *schedule_list = NULL;
+
+/**
+ * scheduled callback.
+ */
+struct nscallback
+{
+ struct nscallback *next;
+ struct timeval tv;
+ void (*callback)(void *p);
+ void *p;
+};
+
+
+/**
+ * Unschedule a callback.
+ *
+ * \param callback callback function
+ * \param p user parameter, passed to callback function
+ *
+ * All scheduled callbacks matching both callback and p are removed.
+ */
+
+static nserror schedule_remove(void (*callback)(void *p), void *p)
+{
+ struct nscallback *cur_nscb;
+ struct nscallback *prev_nscb;
+ struct nscallback *unlnk_nscb;
+
+ /* check there is something on the list to remove */
+ if (schedule_list == NULL) {
+ return NSERROR_OK;
+ }
+
+ SRLOG("removing %p, %p", callback, p);
+
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
+
+ while (cur_nscb != NULL) {
+ if ((cur_nscb->callback == callback) &&
+ (cur_nscb->p == p)) {
+ /* item to remove */
+
+ SRLOG("callback entry %p removing %p(%p)",
+ cur_nscb, cur_nscb->callback, cur_nscb->p);
+
+ /* remove callback */
+ unlnk_nscb = cur_nscb;
+ cur_nscb = unlnk_nscb->next;
+
+ if (prev_nscb == NULL) {
+ schedule_list = cur_nscb;
+ } else {
+ prev_nscb->next = cur_nscb;
+ }
+ free (unlnk_nscb);
+ } else {
+ /* move to next element */
+ prev_nscb = cur_nscb;
+ cur_nscb = prev_nscb->next;
+ }
+ }
+ return NSERROR_OK;
+}
+
+/* exported interface documented in windows/schedule.h */
+nserror win32_schedule(int ival, void (*callback)(void *p), void *p)
+{
+ struct nscallback *nscb;
+ struct timeval tv;
+ nserror ret;
+
+ ret = schedule_remove(callback, p);
+ if ((ival < 0) || (ret != NSERROR_OK)) {
+ return ret;
+ }
+
+ tv.tv_sec = ival / 1000; /* miliseconds to seconds */
+ tv.tv_usec = (ival % 1000) * 1000; /* remainder to microseconds */
+
+ nscb = calloc(1, sizeof(struct nscallback));
+ if (nscb == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ SRLOG("adding callback %p for %p(%p) at %d cs",
+ nscb, callback, p, ival);
+
+ gettimeofday(&nscb->tv, NULL);
+ timeradd(&nscb->tv, &tv, &nscb->tv);
+
+ nscb->callback = callback;
+ nscb->p = p;
+
+ /* add to list front */
+ nscb->next = schedule_list;
+ schedule_list = nscb;
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in schedule.h */
+int
+schedule_run(void)
+{
+ struct timeval tv;
+ struct timeval nexttime;
+ struct timeval rettime;
+ struct nscallback *cur_nscb;
+ struct nscallback *prev_nscb;
+ struct nscallback *unlnk_nscb;
+
+ if (schedule_list == NULL)
+ return -1;
+
+ /* reset enumeration to the start of the list */
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
+ nexttime = cur_nscb->tv;
+
+ gettimeofday(&tv, NULL);
+
+ while (cur_nscb != NULL) {
+ if (timercmp(&tv, &cur_nscb->tv, >)) {
+ /* scheduled time */
+
+ /* remove callback */
+ unlnk_nscb = cur_nscb;
+
+ if (prev_nscb == NULL) {
+ schedule_list = unlnk_nscb->next;
+ } else {
+ prev_nscb->next = unlnk_nscb->next;
+ }
+
+ SRLOG("callback entry %p running %p(%p)",
+ unlnk_nscb, unlnk_nscb->callback, unlnk_nscb->p);
+ /* call callback */
+ unlnk_nscb->callback(unlnk_nscb->p);
+
+ free(unlnk_nscb);
+
+ /* dispatched events can modify the list,
+ * instead of locking we simply reset list
+ * enumeration to the start.
+ */
+ if (schedule_list == NULL)
+ return -1; /* no more callbacks scheduled */
+
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
+ nexttime = cur_nscb->tv;
+ } else {
+ /* if the time to the event is sooner than the
+ * currently recorded soonest event record it
+ */
+ if (timercmp(&nexttime, &cur_nscb->tv, >)) {
+ nexttime = cur_nscb->tv;
+ }
+ /* move to next element */
+ prev_nscb = cur_nscb;
+ cur_nscb = prev_nscb->next;
+ }
+ }
+
+ /* make returned time relative to now */
+ timersub(&nexttime, &tv, &rettime);
+
+ SRLOG("returning time to next event as %ldms",
+ (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
+
+ /* return next event time in milliseconds (24days max wait) */
+ return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
+}
+
+/* exported interface documented in schedule.h */
+void list_schedule(void)
+{
+ struct timeval tv;
+ struct nscallback *cur_nscb;
+
+ gettimeofday(&tv, NULL);
+
+ LOG("schedule list at %ld:%ld", tv.tv_sec, tv.tv_usec);
+
+ cur_nscb = schedule_list;
+
+ while (cur_nscb != NULL) {
+ LOG("Schedule %p at %ld:%ld", cur_nscb, cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
+ cur_nscb = cur_nscb->next;
+ }
+}
+
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/windows/schedule.h b/frontends/windows/schedule.h
new file mode 100644
index 000000000..6d47b2db6
--- /dev/null
+++ b/frontends/windows/schedule.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#ifndef WINDOWS_SCHEDULE_H
+#define WINDOWS_SCHEDULE_H
+
+/**
+ * Schedule a callback.
+ *
+ * \param ival interval before the callback should be made in ms
+ * \param callback callback function
+ * \param p user parameter, passed to callback function
+ *
+ * The callback function will be called as soon as possible after t ms have
+ * passed.
+ */
+nserror win32_schedule(int ival, void (*callback)(void *p), void *p);
+
+/**
+ * Process scheduled callbacks up to current time.
+ *
+ * This walks the list of outstanding scheduled events and dispatches
+ * them if they have met their scheduled time. Due to legacy issues
+ * there are a couple of subtleties with how this operates:
+ *
+ * - Generally there are so few entries on the list the overhead of
+ * ordering the list exceeds the cost of simply enumerating them.
+ *
+ * - The scheduled time is the time *after* which we should call the
+ * operation back, this can result in the next scheduled time
+ * being zero. This is exceedingly rare as the core schedules in
+ * 10ms (cs) quanta and we almost always get called to schedule
+ * after the event time.
+ *
+ * - The callbacks can cause the schedule list to be re-arranged added
+ * to or even completely deleted. This means we must reset the
+ * list enumeration to the beginning every time an event is
+ * dispatched.
+ *
+ * @return The number of milliseconds untill the next scheduled event
+ * or -1 for no event.
+ */
+int schedule_run(void);
+
+/**
+ * LOG all current scheduled events.
+ */
+void list_schedule(void);
+
+#endif
diff --git a/frontends/windows/windbg.c b/frontends/windows/windbg.c
new file mode 100644
index 000000000..ccbecc31e
--- /dev/null
+++ b/frontends/windows/windbg.c
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@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/>.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "windbg.h"
+
+const char *msg_num_to_name(int msg)
+{
+ static char str[256];
+
+ switch (msg) {
+ case 32768:
+ return "WM_APP";
+
+ case 6:
+ return "WM_ACTIVATE ";
+
+ case 28:
+ return "WM_ACTIVATEAPP ";
+
+ case 864:
+ return "WM_AFXFIRST ";
+
+ case 895:
+ return "WM_AFXLAST ";
+
+ case 780:
+ return "WM_ASKCBFORMATNAME ";
+
+ case 75:
+ return "WM_CANCELJOURNAL ";
+
+ case 31:
+ return "WM_CANCELMODE ";
+
+ case 533:
+ return "WM_CAPTURECHANGED ";
+
+ case 781:
+ return "WM_CHANGECBCHAIN ";
+
+ case 258:
+ return "WM_CHAR ";
+
+ case 47:
+ return "WM_CHARTOITEM ";
+
+ case 34:
+ return "WM_CHILDACTIVATE ";
+
+ case 771:
+ return "WM_CLEAR ";
+
+ case 16:
+ return "WM_CLOSE ";
+
+ case 273:
+ return "WM_COMMAND ";
+
+ case 68:
+ return "WM_COMMNOTIFY ";
+
+ case 65:
+ return "WM_COMPACTING ";
+
+ case 57:
+ return "WM_COMPAREITEM ";
+
+ case 123:
+ return "WM_CONTEXTMENU ";
+
+ case 769:
+ return "WM_COPY ";
+
+ case 74:
+ return "WM_COPYDATA ";
+
+ case 1:
+ return "WM_CREATE ";
+
+ case 309:
+ return "WM_CTLCOLORBTN ";
+
+ case 310:
+ return "WM_CTLCOLORDLG ";
+
+ case 307:
+ return "WM_CTLCOLOREDIT ";
+
+ case 308:
+ return "WM_CTLCOLORLISTBOX ";
+
+ case 306:
+ return "WM_CTLCOLORMSGBOX ";
+
+ case 311:
+ return "WM_CTLCOLORSCROLLBAR ";
+
+ case 312:
+ return "WM_CTLCOLORSTATIC ";
+
+ case 768:
+ return "WM_CUT ";
+
+ case 259:
+ return "WM_DEADCHAR ";
+
+ case 45:
+ return "WM_DELETEITEM ";
+
+ case 2:
+ return "WM_DESTROY ";
+
+ case 775:
+ return "WM_DESTROYCLIPBOARD ";
+
+ case 537:
+ return "WM_DEVICECHANGE ";
+
+ case 27:
+ return "WM_DEVMODECHANGE ";
+
+ case 126:
+ return "WM_DISPLAYCHANGE ";
+
+ case 776:
+ return "WM_DRAWCLIPBOARD ";
+
+ case 43:
+ return "WM_DRAWITEM ";
+
+ case 563:
+ return "WM_DROPFILES ";
+
+ case 10:
+ return "WM_ENABLE ";
+
+ case 22:
+ return "WM_ENDSESSION ";
+
+ case 289:
+ return "WM_ENTERIDLE ";
+
+ case 529:
+ return "WM_ENTERMENULOOP ";
+
+ case 561:
+ return "WM_ENTERSIZEMOVE ";
+
+ case 20:
+ return "WM_ERASEBKGND ";
+
+ case 530:
+ return "WM_EXITMENULOOP ";
+
+ case 562:
+ return "WM_EXITSIZEMOVE ";
+
+ case 29:
+ return "WM_FONTCHANGE ";
+
+ case 135:
+ return "WM_GETDLGCODE ";
+
+ case 49:
+ return "WM_GETFONT ";
+
+ case 51:
+ return "WM_GETHOTKEY ";
+
+ case 127:
+ return "WM_GETICON ";
+
+ case 36:
+ return "WM_GETMINMAXINFO ";
+
+ case 13:
+ return "WM_GETTEXT ";
+
+ case 14:
+ return "WM_GETTEXTLENGTH ";
+
+ case 856:
+ return "WM_HANDHELDFIRST ";
+
+ case 863:
+ return "WM_HANDHELDLAST ";
+
+ case 83:
+ return "WM_HELP ";
+
+ case 786:
+ return "WM_HOTKEY ";
+
+ case 276:
+ return "WM_HSCROLL ";
+
+ case 782:
+ return "WM_HSCROLLCLIPBOARD ";
+
+ case 39:
+ return "WM_ICONERASEBKGND ";
+
+ case 272:
+ return "WM_INITDIALOG ";
+
+ case 278:
+ return "WM_INITMENU ";
+
+ case 279:
+ return "WM_INITMENUPOPUP ";
+
+ case 0x00FF:
+ return "WM_INPUT ";
+
+ case 81:
+ return "WM_INPUTLANGCHANGE ";
+
+ case 80:
+ return "WM_INPUTLANGCHANGEREQUEST ";
+
+ case 256:
+ return "WM_KEYDOWN ";
+
+ case 257:
+ return "WM_KEYUP ";
+
+ case 8:
+ return "WM_KILLFOCUS ";
+
+ case 546:
+ return "WM_MDIACTIVATE ";
+
+ case 551:
+ return "WM_MDICASCADE ";
+
+ case 544:
+ return "WM_MDICREATE ";
+
+ case 545:
+ return "WM_MDIDESTROY ";
+
+ case 553:
+ return "WM_MDIGETACTIVE ";
+
+ case 552:
+ return "WM_MDIICONARRANGE ";
+
+ case 549:
+ return "WM_MDIMAXIMIZE ";
+
+ case 548:
+ return "WM_MDINEXT ";
+
+ case 564:
+ return "WM_MDIREFRESHMENU ";
+
+ case 547:
+ return "WM_MDIRESTORE ";
+
+ case 560:
+ return "WM_MDISETMENU ";
+
+ case 550:
+ return "WM_MDITILE ";
+
+ case 44:
+ return "WM_MEASUREITEM ";
+
+ case 0x003D:
+ return "WM_GETOBJECT ";
+
+ case 0x0127:
+ return "WM_CHANGEUISTATE ";
+
+ case 0x0128:
+ return "WM_UPDATEUISTATE ";
+
+ case 0x0129:
+ return "WM_QUERYUISTATE ";
+
+ case 0x0125:
+ return "WM_UNINITMENUPOPUP ";
+
+ case 290:
+ return "WM_MENURBUTTONUP ";
+
+ case 0x0126:
+ return "WM_MENUCOMMAND ";
+
+ case 0x0124:
+ return "WM_MENUGETOBJECT ";
+
+ case 0x0123:
+ return "WM_MENUDRAG ";
+
+ case 0x0319:
+ return "WM_APPCOMMAND ";
+
+ case 288:
+ return "WM_MENUCHAR ";
+
+ case 287:
+ return "WM_MENUSELECT ";
+
+ case 531:
+ return "WM_NEXTMENU ";
+
+ case 3:
+ return "WM_MOVE ";
+
+ case 534:
+ return "WM_MOVING ";
+
+ case 134:
+ return "WM_NCACTIVATE ";
+
+ case 131:
+ return "WM_NCCALCSIZE ";
+
+ case 129:
+ return "WM_NCCREATE ";
+
+ case 130:
+ return "WM_NCDESTROY ";
+
+ case 132:
+ return "WM_NCHITTEST ";
+
+ case 163:
+ return "WM_NCLBUTTONDBLCLK ";
+
+ case 161:
+ return "WM_NCLBUTTONDOWN ";
+
+ case 162:
+ return "WM_NCLBUTTONUP ";
+
+ case 169:
+ return "WM_NCMBUTTONDBLCLK ";
+
+ case 167:
+ return "WM_NCMBUTTONDOWN ";
+
+ case 168:
+ return "WM_NCMBUTTONUP ";
+
+ case 171:
+ return "WM_NCXBUTTONDOWN ";
+
+ case 172:
+ return "WM_NCXBUTTONUP ";
+
+ case 173:
+ return "WM_NCXBUTTONDBLCLK ";
+
+ case 0x02A0:
+ return "WM_NCMOUSEHOVER ";
+
+ case 0x02A2:
+ return "WM_NCMOUSELEAVE ";
+
+ case 160:
+ return "WM_NCMOUSEMOVE ";
+
+ case 133:
+ return "WM_NCPAINT ";
+
+ case 166:
+ return "WM_NCRBUTTONDBLCLK ";
+
+ case 164:
+ return "WM_NCRBUTTONDOWN ";
+
+ case 165:
+ return "WM_NCRBUTTONUP ";
+
+ case 40:
+ return "WM_NEXTDLGCTL ";
+
+ case 78:
+ return "WM_NOTIFY ";
+
+ case 85:
+ return "WM_NOTIFYFORMAT ";
+
+ case 0:
+ return "WM_NULL ";
+
+ case 15:
+ return "WM_PAINT ";
+
+ case 777:
+ return "WM_PAINTCLIPBOARD ";
+
+ case 38:
+ return "WM_PAINTICON ";
+
+ case 785:
+ return "WM_PALETTECHANGED ";
+
+ case 784:
+ return "WM_PALETTEISCHANGING ";
+
+ case 528:
+ return "WM_PARENTNOTIFY ";
+
+ case 770:
+ return "WM_PASTE ";
+
+ case 896:
+ return "WM_PENWINFIRST ";
+
+ case 911:
+ return "WM_PENWINLAST ";
+
+ case 72:
+ return "WM_POWER ";
+
+ case 536:
+ return "WM_POWERBROADCAST ";
+
+ case 791:
+ return "WM_PRINT ";
+
+ case 792:
+ return "WM_PRINTCLIENT ";
+
+ case 55:
+ return "WM_QUERYDRAGICON ";
+
+ case 17:
+ return "WM_QUERYENDSESSION ";
+
+ case 783:
+ return "WM_QUERYNEWPALETTE ";
+
+ case 19:
+ return "WM_QUERYOPEN ";
+
+ case 35:
+ return "WM_QUEUESYNC ";
+
+ case 18:
+ return "WM_QUIT ";
+
+ case 774:
+ return "WM_RENDERALLFORMATS ";
+
+ case 773:
+ return "WM_RENDERFORMAT ";
+
+ case 32:
+ return "WM_SETCURSOR ";
+
+ case 7:
+ return "WM_SETFOCUS ";
+
+ case 48:
+ return "WM_SETFONT ";
+
+ case 50:
+ return "WM_SETHOTKEY ";
+
+ case 128:
+ return "WM_SETICON ";
+
+ case 11:
+ return "WM_SETREDRAW ";
+
+ case 12:
+ return "WM_SETTEXT ";
+
+ case 26:
+ return "WM_SETTINGCHANGE ";
+
+ case 24:
+ return "WM_SHOWWINDOW ";
+
+ case 5:
+ return "WM_SIZE ";
+
+ case 779:
+ return "WM_SIZECLIPBOARD ";
+
+ case 532:
+ return "WM_SIZING ";
+
+ case 42:
+ return "WM_SPOOLERSTATUS ";
+
+ case 125:
+ return "WM_STYLECHANGED ";
+
+ case 124:
+ return "WM_STYLECHANGING ";
+
+ case 262:
+ return "WM_SYSCHAR ";
+
+ case 21:
+ return "WM_SYSCOLORCHANGE ";
+
+ case 274:
+ return "WM_SYSCOMMAND ";
+
+ case 263:
+ return "WM_SYSDEADCHAR ";
+
+ case 260:
+ return "WM_SYSKEYDOWN ";
+
+ case 261:
+ return "WM_SYSKEYUP ";
+
+ case 82:
+ return "WM_TCARD ";
+
+ case 794:
+ return "WM_THEMECHANGED ";
+
+ case 30:
+ return "WM_TIMECHANGE ";
+
+ case 275:
+ return "WM_TIMER ";
+
+ case 772:
+ return "WM_UNDO ";
+
+ case 1024:
+ return "WM_USER ";
+
+ case 84:
+ return "WM_USERCHANGED ";
+
+ case 46:
+ return "WM_VKEYTOITEM ";
+
+ case 277:
+ return "WM_VSCROLL ";
+
+ case 778:
+ return "WM_VSCROLLCLIPBOARD ";
+
+ case 71:
+ return "WM_WINDOWPOSCHANGED ";
+
+ case 70:
+ return "WM_WINDOWPOSCHANGING ";
+
+ case 264:
+ return "WM_KEYLAST ";
+
+ case 136:
+ return "WM_SYNCPAINT ";
+
+ case 33:
+ return "WM_MOUSEACTIVATE ";
+
+ case 512:
+ return "WM_MOUSEMOVE ";
+
+ case 513:
+ return "WM_LBUTTONDOWN ";
+
+ case 514:
+ return "WM_LBUTTONUP ";
+
+ case 515:
+ return "WM_LBUTTONDBLCLK ";
+
+ case 516:
+ return "WM_RBUTTONDOWN ";
+
+ case 517:
+ return "WM_RBUTTONUP ";
+
+ case 518:
+ return "WM_RBUTTONDBLCLK ";
+
+ case 519:
+ return "WM_MBUTTONDOWN ";
+
+ case 520:
+ return "WM_MBUTTONUP ";
+
+ case 521:
+ return "WM_MBUTTONDBLCLK ";
+
+ case 522:
+ return "WM_MOUSEWHEEL ";
+
+ case 523:
+ return "WM_XBUTTONDOWN ";
+
+ case 524:
+ return "WM_XBUTTONUP ";
+
+ case 525:
+ return "WM_XBUTTONDBLCLK ";
+
+ case 0x2A1:
+ return "WM_MOUSEHOVER ";
+
+ case 0x2A3:
+ return "WM_MOUSELEAVE ";
+
+ }
+
+ sprintf(str,"%d",msg);
+
+ return str;
+}
+
+void win_perror(const char * lpszFunction)
+{
+ /* Retrieve the system error message for the last-error code */
+
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+ DWORD dw = GetLastError();
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ /* Display the error message and exit the process */
+
+ lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
+
+ snprintf((LPTSTR)lpDisplayBuf,
+ LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ TEXT("%s failed with error %ld: %s"),
+ lpszFunction, dw, (char *)lpMsgBuf);
+ MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
+
+ LocalFree(lpMsgBuf);
+ LocalFree(lpDisplayBuf);
+}
diff --git a/frontends/windows/windbg.h b/frontends/windows/windbg.h
new file mode 100644
index 000000000..b2d8640f4
--- /dev/null
+++ b/frontends/windows/windbg.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_WINDBG_H_
+#define _NETSURF_WINDOWS_WINDBG_H_
+
+#include "utils/log.h"
+
+const char *msg_num_to_name(int msg);
+void win_perror(const char *lpszFunction);
+
+#define LOG_WIN_MSG(h, m, w, l) \
+ if (((m) != WM_SETCURSOR) && \
+ ((m) != WM_MOUSEMOVE) && \
+ ((m) != WM_NCHITTEST) && \
+ ((m) != WM_ENTERIDLE)) \
+ LOG("%s, hwnd %p, w 0x%x, l 0x%Ix", msg_num_to_name(m), h, w, l);
+
+#endif
diff --git a/frontends/windows/window.c b/frontends/windows/window.c
new file mode 100644
index 000000000..f5f13fe24
--- /dev/null
+++ b/frontends/windows/window.c
@@ -0,0 +1,1741 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#include "utils/config.h"
+
+#include <stdbool.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
+#include "utils/messages.h"
+#include "content/content.h"
+#include "desktop/browser.h"
+#include "desktop/gui_window.h"
+#include "desktop/browser_history.h"
+#include "desktop/textinput.h"
+
+#include "windows/gui.h"
+#include "windows/pointers.h"
+#include "windows/about.h"
+#include "windows/resourceid.h"
+#include "windows/findfile.h"
+#include "windows/windbg.h"
+#include "windows/drawable.h"
+#include "windows/font.h"
+#include "windows/prefs.h"
+#include "windows/localhistory.h"
+#include "windows/window.h"
+
+/** List of all our gui windows */
+static struct gui_window *window_list = NULL;
+
+/** The main window class name */
+static const char windowclassname_main[] = "nswsmainwindow";
+
+/** width of the throbber element */
+#define NSWS_THROBBER_WIDTH 24
+
+/** Number of open windows */
+static int open_windows = 0;
+
+
+/**
+ * Obtain the DPI of the display.
+ */
+static int get_window_dpi(HWND hwnd)
+{
+ HDC hdc = GetDC(hwnd);
+ int dpi = GetDeviceCaps(hdc, LOGPIXELSY);
+
+ if (dpi <= 10) {
+ dpi = 96; /* 96DPI is the default */
+ }
+
+ ReleaseDC(hwnd, hdc);
+
+ LOG("FIX DPI %d", dpi);
+
+ return dpi;
+}
+
+
+/**
+ * set accelerators
+ */
+static void nsws_window_set_accels(struct gui_window *w)
+{
+ int i, nitems = 13;
+ ACCEL accels[nitems];
+
+ for (i = 0; i < nitems; i++) {
+ accels[i].fVirt = FCONTROL | FVIRTKEY;
+ }
+
+ accels[0].key = 0x51; /* Q */
+ accels[0].cmd = IDM_FILE_QUIT;
+ accels[1].key = 0x4E; /* N */
+ accels[1].cmd = IDM_FILE_OPEN_WINDOW;
+ accels[2].key = VK_LEFT;
+ accels[2].cmd = IDM_NAV_BACK;
+ accels[3].key = VK_RIGHT;
+ accels[3].cmd = IDM_NAV_FORWARD;
+ accels[4].key = VK_UP;
+ accels[4].cmd = IDM_NAV_HOME;
+ accels[5].key = VK_BACK;
+ accels[5].cmd = IDM_NAV_STOP;
+ accels[6].key = VK_SPACE;
+ accels[6].cmd = IDM_NAV_RELOAD;
+ accels[7].key = 0x4C; /* L */
+ accels[7].cmd = IDM_FILE_OPEN_LOCATION;
+ accels[8].key = 0x57; /* w */
+ accels[8].cmd = IDM_FILE_CLOSE_WINDOW;
+ accels[9].key = 0x41; /* A */
+ accels[9].cmd = IDM_EDIT_SELECT_ALL;
+ accels[10].key = VK_F8;
+ accels[10].cmd = IDM_VIEW_SOURCE;
+ accels[11].key = VK_RETURN;
+ accels[11].fVirt = FVIRTKEY;
+ accels[11].cmd = IDC_MAIN_LAUNCH_URL;
+ accels[12].key = VK_F11;
+ accels[12].fVirt = FVIRTKEY;
+ accels[12].cmd = IDM_VIEW_FULLSCREEN;
+
+ w->acceltable = CreateAcceleratorTable(accels, nitems);
+}
+
+
+/**
+ * creation of a new full browser window
+ */
+static HWND nsws_window_create(struct gui_window *gw)
+{
+ HWND hwnd;
+ INITCOMMONCONTROLSEX icc;
+
+ LOG("GUI window %p", gw);
+
+ icc.dwSize = sizeof(icc);
+ icc.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
+#if WINVER > 0x0501
+ icc.dwICC |= ICC_STANDARD_CLASSES;
+#endif
+ InitCommonControlsEx(&icc);
+
+ gw->mainmenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU_MAIN));
+ gw->rclick = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU_CONTEXT));
+
+ LOG("creating window for hInstance %p", hInstance);
+ hwnd = CreateWindowEx(0,
+ windowclassname_main,
+ "NetSurf Browser",
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_DBLCLKS,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ gw->width,
+ gw->height,
+ NULL,
+ gw->mainmenu,
+ hInstance,
+ NULL);
+
+ if (hwnd == NULL) {
+ LOG("Window create failed");
+ return NULL;
+ }
+
+ /* set the gui window associated with this browser */
+ SetProp(hwnd, TEXT("GuiWnd"), (HANDLE)gw);
+
+ browser_set_dpi(get_window_dpi(hwnd));
+
+ if ((nsoption_int(window_width) >= 100) &&
+ (nsoption_int(window_height) >= 100) &&
+ (nsoption_int(window_x) >= 0) &&
+ (nsoption_int(window_y) >= 0)) {
+ LOG("Setting Window position %d,%d %d,%d", nsoption_int(window_x), nsoption_int(window_y), nsoption_int(window_width), nsoption_int(window_height));
+ SetWindowPos(hwnd, HWND_TOP,
+ nsoption_int(window_x), nsoption_int(window_y),
+ nsoption_int(window_width), nsoption_int(window_height),
+ SWP_SHOWWINDOW);
+ }
+
+ nsws_window_set_accels(gw);
+
+ return hwnd;
+}
+
+
+/**
+ * calculate the dimensions of the url bar relative to the parent toolbar
+ */
+static void
+urlbar_dimensions(HWND hWndParent,
+ int toolbuttonsize,
+ int buttonc,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ RECT rc;
+ const int cy_edit = 23;
+
+ GetClientRect(hWndParent, &rc);
+ *x = (toolbuttonsize + 1) * (buttonc + 1) + (NSWS_THROBBER_WIDTH>>1);
+ *y = ((((rc.bottom - 1) - cy_edit) >> 1) * 2) / 3;
+ *width = (rc.right - 1) - *x - (NSWS_THROBBER_WIDTH>>1) - NSWS_THROBBER_WIDTH;
+ *height = cy_edit;
+}
+
+
+
+static LRESULT
+nsws_window_toolbar_command(struct gui_window *gw,
+ int notification_code,
+ int identifier,
+ HWND ctrl_window)
+{
+ LOG("notification_code %d identifier %d ctrl_window %p", notification_code, identifier, ctrl_window);
+
+ switch(identifier) {
+
+ case IDC_MAIN_URLBAR:
+ switch (notification_code) {
+ case EN_CHANGE:
+ LOG("EN_CHANGE");
+ break;
+
+ case EN_ERRSPACE:
+ LOG("EN_ERRSPACE");
+ break;
+
+ case EN_HSCROLL:
+ LOG("EN_HSCROLL");
+ break;
+
+ case EN_KILLFOCUS:
+ LOG("EN_KILLFOCUS");
+ break;
+
+ case EN_MAXTEXT:
+ LOG("EN_MAXTEXT");
+ break;
+
+ case EN_SETFOCUS:
+ LOG("EN_SETFOCUS");
+ break;
+
+ case EN_UPDATE:
+ LOG("EN_UPDATE");
+ break;
+
+ case EN_VSCROLL:
+ LOG("EN_VSCROLL");
+ break;
+
+ default:
+ LOG("Unknown notification_code");
+ break;
+ }
+ break;
+
+ default:
+ return 1; /* unhandled */
+
+ }
+ return 0; /* control message handled */
+}
+
+
+/**
+ * callback for toolbar events
+ */
+static LRESULT CALLBACK
+nsws_window_toolbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ struct gui_window *gw;
+ int urlx, urly, urlwidth, urlheight;
+ WNDPROC toolproc;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ gw = nsws_get_gui_window(hwnd);
+
+ switch (msg) {
+ case WM_SIZE:
+ urlbar_dimensions(hwnd,
+ gw->toolbuttonsize,
+ gw->toolbuttonc,
+ &urlx, &urly, &urlwidth, &urlheight);
+
+ /* resize url */
+ if (gw->urlbar != NULL) {
+ MoveWindow(gw->urlbar,
+ urlx, urly,
+ urlwidth, urlheight,
+ true);
+ }
+
+ /* move throbber */
+ if (gw->throbber != NULL) {
+ MoveWindow(gw->throbber,
+ LOWORD(lparam) - NSWS_THROBBER_WIDTH - 4, 8,
+ NSWS_THROBBER_WIDTH, NSWS_THROBBER_WIDTH,
+ true);
+ }
+ break;
+
+ case WM_COMMAND:
+ if (nsws_window_toolbar_command(gw,
+ HIWORD(wparam),
+ LOWORD(wparam),
+ (HWND)lparam) == 0) {
+ return 0;
+ }
+ break;
+ }
+
+ /* remove properties if window is being destroyed */
+ if (msg == WM_NCDESTROY) {
+ RemoveProp(hwnd, TEXT("GuiWnd"));
+ toolproc = (WNDPROC)RemoveProp(hwnd, TEXT("OrigMsgProc"));
+ } else {
+ toolproc = (WNDPROC)GetProp(hwnd, TEXT("OrigMsgProc"));
+ }
+
+ if (toolproc == NULL) {
+ /* the original toolbar procedure is not available */
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ /* chain to the next handler */
+ return CallWindowProc(toolproc, hwnd, msg, wparam, lparam);
+}
+
+
+static HIMAGELIST
+get_imagelist(int resid, int bsize, int bcnt)
+{
+ HIMAGELIST hImageList;
+ HBITMAP hScrBM;
+
+ LOG("resource id %d, bzize %d, bcnt %d", resid, bsize, bcnt);
+
+ hImageList = ImageList_Create(bsize, bsize, ILC_COLOR24 | ILC_MASK, 0,
+ bcnt);
+ if (hImageList == NULL)
+ return NULL;
+
+ hScrBM = LoadImage(hInstance, MAKEINTRESOURCE(resid),
+ IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+
+ if (hScrBM == NULL) {
+ win_perror("LoadImage");
+ return NULL;
+ }
+
+ if (ImageList_AddMasked(hImageList, hScrBM, 0xcccccc) == -1) {
+ /* failed to add masked bitmap */
+ ImageList_Destroy(hImageList);
+ hImageList = NULL;
+ }
+ DeleteObject(hScrBM);
+
+ return hImageList;
+}
+
+
+/**
+ * callback for url bar events
+ */
+static LRESULT CALLBACK
+nsws_window_urlbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ struct gui_window *gw;
+ WNDPROC urlproc;
+ HFONT hFont;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ gw = nsws_get_gui_window(hwnd);
+
+ urlproc = (WNDPROC)GetProp(hwnd, TEXT("OrigMsgProc"));
+
+ /* override messages */
+ switch (msg) {
+ case WM_CHAR:
+ if (wparam == 13) {
+ SendMessage(gw->main, WM_COMMAND, IDC_MAIN_LAUNCH_URL, 0);
+ return 0;
+ }
+ break;
+
+ case WM_DESTROY:
+ hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
+ if (hFont != NULL) {
+ LOG("Destroyed font object");
+ DeleteObject(hFont);
+ }
+
+
+ case WM_NCDESTROY:
+ /* remove properties if window is being destroyed */
+ RemoveProp(hwnd, TEXT("GuiWnd"));
+ RemoveProp(hwnd, TEXT("OrigMsgProc"));
+ break;
+ }
+
+ if (urlproc == NULL) {
+ /* the original toolbar procedure is not available */
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ /* chain to the next handler */
+ return CallWindowProc(urlproc, hwnd, msg, wparam, lparam);
+}
+
+
+/**
+ * create a urlbar and message handler
+ *
+ * Create an Edit control for enerting urls
+ */
+static HWND
+nsws_window_urlbar_create(struct gui_window *gw, HWND hwndparent)
+{
+ int urlx, urly, urlwidth, urlheight;
+ HWND hwnd;
+ WNDPROC urlproc;
+ HFONT hFont;
+
+ urlbar_dimensions(hwndparent,
+ gw->toolbuttonsize,
+ gw->toolbuttonc,
+ &urlx, &urly, &urlwidth, &urlheight);
+
+ /* Create the edit control */
+ hwnd = CreateWindowEx(0L,
+ TEXT("Edit"),
+ NULL,
+ WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
+ urlx,
+ urly,
+ urlwidth,
+ urlheight,
+ hwndparent,
+ (HMENU)IDC_MAIN_URLBAR,
+ hInstance,
+ 0);
+
+ if (hwnd == NULL) {
+ return NULL;
+ }
+
+ /* set the gui window associated with this control */
+ SetProp(hwnd, TEXT("GuiWnd"), (HANDLE)gw);
+
+ /* subclass the message handler */
+ urlproc = (WNDPROC)SetWindowLongPtr(hwnd,
+ GWLP_WNDPROC,
+ (LONG_PTR)nsws_window_urlbar_callback);
+
+ /* save the real handler */
+ SetProp(hwnd, TEXT("OrigMsgProc"), (HANDLE)urlproc);
+
+ hFont = CreateFont(urlheight - 4, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
+ if (hFont != NULL) {
+ LOG("Setting font object");
+ SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, 0);
+ }
+
+ LOG("Created url bar hwnd:%p, x:%d, y:%d, w:%d, h:%d", hwnd, urlx, urly, urlwidth, urlheight);
+
+ return hwnd;
+}
+
+
+/**
+ * creation of throbber
+ */
+static HWND
+nsws_window_throbber_create(struct gui_window *w)
+{
+ HWND hwnd;
+ char avi[PATH_MAX];
+
+ hwnd = CreateWindow(ANIMATE_CLASS,
+ "",
+ WS_CHILD | WS_VISIBLE | ACS_TRANSPARENT,
+ w->width - NSWS_THROBBER_WIDTH - 4,
+ 8,
+ NSWS_THROBBER_WIDTH,
+ NSWS_THROBBER_WIDTH,
+ w->main,
+ (HMENU) IDC_MAIN_THROBBER,
+ hInstance,
+ NULL);
+
+ nsws_find_resource(avi, "throbber.avi", "windows/res/throbber.avi");
+ LOG("setting throbber avi as %s", avi);
+ Animate_Open(hwnd, avi);
+ if (w->throbbing)
+ Animate_Play(hwnd, 0, -1, -1);
+ else
+ Animate_Seek(hwnd, 0);
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ return hwnd;
+}
+
+
+/* create a toolbar add controls and message handler */
+static HWND
+nsws_window_create_toolbar(struct gui_window *gw, HWND hWndParent)
+{
+ HIMAGELIST hImageList;
+ HWND hWndToolbar;
+ /* Toolbar buttons */
+ TBBUTTON tbButtons[] = {
+ {0, IDM_NAV_BACK, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
+ {1, IDM_NAV_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
+ {2, IDM_NAV_HOME, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
+ {3, IDM_NAV_RELOAD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
+ {4, IDM_NAV_STOP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
+ };
+ WNDPROC toolproc;
+
+ /* Create the toolbar window and subclass its message handler. */
+ hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, "Toolbar",
+ WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT,
+ 0, 0, 0, 0,
+ hWndParent, NULL, HINST_COMMCTRL, NULL);
+ if (!hWndToolbar) {
+ return NULL;
+ }
+
+ /* set the gui window associated with this toolbar */
+ SetProp(hWndToolbar, TEXT("GuiWnd"), (HANDLE)gw);
+
+ /* subclass the message handler */
+ toolproc = (WNDPROC)SetWindowLongPtr(hWndToolbar,
+ GWLP_WNDPROC,
+ (LONG_PTR)nsws_window_toolbar_callback);
+
+ /* save the real handler */
+ SetProp(hWndToolbar, TEXT("OrigMsgProc"), (HANDLE)toolproc);
+
+ /* remember how many buttons are being created */
+ gw->toolbuttonc = sizeof(tbButtons) / sizeof(TBBUTTON);
+
+ /* Create the standard image list and assign to toolbar. */
+ hImageList = get_imagelist(IDR_TOOLBAR_BITMAP,
+ gw->toolbuttonsize,
+ gw->toolbuttonc);
+ if (hImageList != NULL) {
+ SendMessage(hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)hImageList);
+ }
+
+ /* Create the disabled image list and assign to toolbar. */
+ hImageList = get_imagelist(IDR_TOOLBAR_BITMAP_GREY,
+ gw->toolbuttonsize,
+ gw->toolbuttonc);
+ if (hImageList != NULL) {
+ SendMessage(hWndToolbar, TB_SETDISABLEDIMAGELIST, 0,
+ (LPARAM)hImageList);
+ }
+
+ /* Create the hot image list and assign to toolbar. */
+ hImageList = get_imagelist(IDR_TOOLBAR_BITMAP_HOT,
+ gw->toolbuttonsize,
+ gw->toolbuttonc);
+ if (hImageList != NULL) {
+ SendMessage(hWndToolbar, TB_SETHOTIMAGELIST, 0,
+ (LPARAM)hImageList);
+ }
+
+ /* Add buttons. */
+ SendMessage(hWndToolbar,
+ TB_BUTTONSTRUCTSIZE,
+ (WPARAM)sizeof(TBBUTTON),
+ 0);
+ SendMessage(hWndToolbar,
+ TB_ADDBUTTONS,
+ (WPARAM)gw->toolbuttonc,
+ (LPARAM)&tbButtons);
+
+ gw->urlbar = nsws_window_urlbar_create(gw, hWndToolbar);
+
+ gw->throbber = nsws_window_throbber_create(gw);
+
+ return hWndToolbar;
+}
+
+
+/**
+ * creation of status bar
+ */
+static HWND nsws_window_create_statusbar(struct gui_window *w)
+{
+ HWND hwnd = CreateWindowEx(0,
+ STATUSCLASSNAME,
+ NULL,
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, 0, 0,
+ w->main,
+ (HMENU)IDC_MAIN_STATUSBAR,
+ hInstance,
+ NULL);
+ SendMessage(hwnd, SB_SETTEXT, 0, (LPARAM)"NetSurf");
+ return hwnd;
+}
+
+
+static void nsws_update_edit(struct gui_window *w)
+{
+ browser_editor_flags editor_flags = (w->bw == NULL) ?
+ BW_EDITOR_NONE : browser_window_get_editor_flags(w->bw);
+ bool paste, copy, del;
+ bool sel = (editor_flags & BW_EDITOR_CAN_COPY);
+ if (GetFocus() == w->urlbar) {
+ DWORD i, ii;
+ SendMessage(w->urlbar, EM_GETSEL, (WPARAM)&i, (LPARAM)&ii);
+ paste = true;
+ copy = (i != ii);
+ del = (i != ii);
+
+ } else if (sel){
+ paste = (editor_flags & BW_EDITOR_CAN_PASTE);
+ copy = sel;
+ del = (editor_flags & BW_EDITOR_CAN_CUT);
+ } else {
+ paste = false;
+ copy = false;
+ del = false;
+ }
+ EnableMenuItem(w->mainmenu,
+ IDM_EDIT_PASTE,
+ (paste ? MF_ENABLED : MF_GRAYED));
+
+ EnableMenuItem(w->rclick,
+ IDM_EDIT_PASTE,
+ (paste ? MF_ENABLED : MF_GRAYED));
+
+ EnableMenuItem(w->mainmenu,
+ IDM_EDIT_COPY,
+ (copy ? MF_ENABLED : MF_GRAYED));
+
+ EnableMenuItem(w->rclick,
+ IDM_EDIT_COPY,
+ (copy ? MF_ENABLED : MF_GRAYED));
+
+ if (del == true) {
+ EnableMenuItem(w->mainmenu, IDM_EDIT_CUT, MF_ENABLED);
+ EnableMenuItem(w->mainmenu, IDM_EDIT_DELETE, MF_ENABLED);
+ EnableMenuItem(w->rclick, IDM_EDIT_CUT, MF_ENABLED);
+ EnableMenuItem(w->rclick, IDM_EDIT_DELETE, MF_ENABLED);
+ } else {
+ EnableMenuItem(w->mainmenu, IDM_EDIT_CUT, MF_GRAYED);
+ EnableMenuItem(w->mainmenu, IDM_EDIT_DELETE, MF_GRAYED);
+ EnableMenuItem(w->rclick, IDM_EDIT_CUT, MF_GRAYED);
+ EnableMenuItem(w->rclick, IDM_EDIT_DELETE, MF_GRAYED);
+ }
+}
+
+
+static bool
+nsws_ctx_menu(struct gui_window *w, HWND hwnd, int x, int y)
+{
+ RECT rc; /* client area of window */
+ POINT pt = { x, y }; /* location of mouse click */
+
+ /* Get the bounding rectangle of the client area. */
+ GetClientRect(hwnd, &rc);
+
+ /* Convert the mouse position to client coordinates. */
+ ScreenToClient(hwnd, &pt);
+
+ /* If the position is in the client area, display a shortcut menu. */
+ if (PtInRect(&rc, pt)) {
+ ClientToScreen(hwnd, &pt);
+ nsws_update_edit(w);
+ TrackPopupMenu(GetSubMenu(w->rclick, 0),
+ TPM_CENTERALIGN | TPM_TOPALIGN,
+ x,
+ y,
+ 0,
+ hwnd,
+ NULL);
+
+ return true;
+ }
+
+ /* Return false if no menu is displayed. */
+ return false;
+}
+
+
+/**
+ * update state of forward/back buttons/menu items when page changes
+ */
+static void nsws_window_update_forward_back(struct gui_window *w)
+{
+ if (w->bw == NULL)
+ return;
+
+ bool forward = browser_window_history_forward_available(w->bw);
+ bool back = browser_window_history_back_available(w->bw);
+
+ if (w->mainmenu != NULL) {
+ EnableMenuItem(w->mainmenu, IDM_NAV_FORWARD,
+ (forward ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(w->mainmenu, IDM_NAV_BACK,
+ (back ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(w->rclick, IDM_NAV_FORWARD,
+ (forward ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(w->rclick, IDM_NAV_BACK,
+ (back ? MF_ENABLED : MF_GRAYED));
+ }
+
+ if (w->toolbar != NULL) {
+ SendMessage(w->toolbar, TB_SETSTATE,
+ (WPARAM) IDM_NAV_FORWARD,
+ MAKELONG((forward ? TBSTATE_ENABLED :
+ TBSTATE_INDETERMINATE), 0));
+ SendMessage(w->toolbar, TB_SETSTATE,
+ (WPARAM) IDM_NAV_BACK,
+ MAKELONG((back ? TBSTATE_ENABLED :
+ TBSTATE_INDETERMINATE), 0));
+ }
+}
+
+
+static bool win32_window_get_scroll(struct gui_window *w, int *sx, int *sy)
+{
+ LOG("get scroll");
+ if (w == NULL)
+ return false;
+
+ *sx = w->scrollx;
+ *sy = w->scrolly;
+
+ return true;
+}
+
+
+static void nsws_set_scale(struct gui_window *gw, float scale)
+{
+ assert(gw != NULL);
+
+ if (gw->scale == scale)
+ return;
+
+ gw->scale = scale;
+
+ if (gw->bw == NULL)
+ return;
+
+ browser_window_set_scale(gw->bw, scale, true);
+}
+
+
+/**
+ * redraw the whole window
+ */
+static void win32_window_redraw_window(struct gui_window *gw)
+{
+ /* LOG("gw:%p", gw); */
+ if (gw != NULL) {
+ RedrawWindow(gw->drawingarea, NULL, NULL,
+ RDW_INVALIDATE | RDW_NOERASE);
+ }
+}
+
+
+/**
+ * scroll the window
+ *
+ * \param w The win32 gui window to scroll.
+ * \param sx the new 'absolute' horizontal scroll location
+ * \param sy the new 'absolute' vertical scroll location
+ */
+void win32_window_set_scroll(struct gui_window *w, int sx, int sy)
+{
+ SCROLLINFO si;
+ nserror err;
+ int height;
+ int width;
+ POINT p;
+
+ if ((w == NULL) || (w->bw == NULL))
+ return;
+
+ err = browser_window_get_extents(w->bw, true, &width, &height);
+ if (err != NSERROR_OK) {
+ return;
+ }
+
+ /*LOG("scroll sx,sy:%d,%d x,y:%d,%d w.h:%d,%d",sx,sy,w->scrollx,w->scrolly, width,height);*/
+
+ /* The resulting gui window scroll must remain withn the
+ * windows bounding box.
+ */
+ if (sx < 0) {
+ w->requestscrollx = -w->scrollx;
+ } else if (sx > (width - w->width)) {
+ w->requestscrollx = (width - w->width) - w->scrollx;
+ } else {
+ w->requestscrollx = sx - w->scrollx;
+ }
+ if (sy < 0) {
+ w->requestscrolly = -w->scrolly;
+ } else if (sy > (height - w->height)) {
+ w->requestscrolly = (height - w->height) - w->scrolly;
+ } else {
+ w->requestscrolly = sy - w->scrolly;
+ }
+
+ /*LOG("requestscroll x,y:%d,%d", w->requestscrollx, w->requestscrolly);*/
+
+ /* set the vertical scroll offset */
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = height - 1;
+ si.nPage = w->height;
+ si.nPos = max(w->scrolly + w->requestscrolly, 0);
+ si.nPos = min(si.nPos, height - w->height);
+ SetScrollInfo(w->drawingarea, SB_VERT, &si, TRUE);
+ /*LOG("SetScrollInfo VERT min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos);*/
+
+ /* set the horizontal scroll offset */
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = width -1;
+ si.nPage = w->width;
+ si.nPos = max(w->scrollx + w->requestscrollx, 0);
+ si.nPos = min(si.nPos, width - w->width);
+ SetScrollInfo(w->drawingarea, SB_HORZ, &si, TRUE);
+ /*LOG("SetScrollInfo HORZ min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos);*/
+
+ /* Set caret position */
+ GetCaretPos(&p);
+ HideCaret(w->drawingarea);
+ SetCaretPos(p.x - w->requestscrollx, p.y - w->requestscrolly);
+ ShowCaret(w->drawingarea);
+
+ RECT r, redraw;
+ r.top = 0;
+ r.bottom = w->height + 1;
+ r.left = 0;
+ r.right = w->width + 1;
+ ScrollWindowEx(w->drawingarea, - w->requestscrollx, - w->requestscrolly, &r, NULL, NULL, &redraw, SW_INVALIDATE);
+ /*LOG("ScrollWindowEx %d, %d", - w->requestscrollx, - w->requestscrolly);*/
+ w->scrolly += w->requestscrolly;
+ w->scrollx += w->requestscrollx;
+ w->requestscrollx = 0;
+ w->requestscrolly = 0;
+
+}
+
+/**
+ * Create a new window due to menu selection
+ *
+ * \param gw frontends graphical window.
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+static nserror win32_open_new_window(struct gui_window *gw)
+{
+ const char *addr;
+ nsurl *url;
+ nserror ret;
+
+ if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ } else {
+ addr = NETSURF_HOMEPAGE;
+ }
+
+ ret = nsurl_create(addr, &url);
+ if (ret == NSERROR_OK) {
+ ret = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ gw->bw,
+ NULL);
+ nsurl_unref(url);
+ }
+
+ return ret;
+}
+
+static LRESULT
+nsws_window_command(HWND hwnd,
+ struct gui_window *gw,
+ int notification_code,
+ int identifier,
+ HWND ctrl_window)
+{
+ nserror ret;
+
+ LOG("notification_code %x identifier %x ctrl_window %p",
+ notification_code, identifier, ctrl_window);
+
+ switch(identifier) {
+
+ case IDM_FILE_QUIT:
+ {
+ struct gui_window *w;
+ w = window_list;
+ while (w != NULL) {
+ PostMessage(w->main, WM_CLOSE, 0, 0);
+ w = w->next;
+ }
+ break;
+ }
+
+ case IDM_FILE_OPEN_LOCATION:
+ SetFocus(gw->urlbar);
+ break;
+
+ case IDM_FILE_OPEN_WINDOW:
+ ret = win32_open_new_window(gw);
+ if (ret != NSERROR_OK) {
+ win32_warning(messages_get_errorcode(ret), 0);
+ }
+ break;
+
+ case IDM_FILE_CLOSE_WINDOW:
+ PostMessage(gw->main, WM_CLOSE, 0, 0);
+ break;
+
+ case IDM_FILE_SAVE_PAGE:
+ break;
+
+ case IDM_FILE_SAVEAS_TEXT:
+ break;
+
+ case IDM_FILE_SAVEAS_PDF:
+ break;
+
+ case IDM_FILE_SAVEAS_POSTSCRIPT:
+ break;
+
+ case IDM_FILE_PRINT_PREVIEW:
+ break;
+
+ case IDM_FILE_PRINT:
+ break;
+
+ case IDM_EDIT_CUT:
+ OpenClipboard(gw->main);
+ EmptyClipboard();
+ CloseClipboard();
+ if (GetFocus() == gw->urlbar) {
+ SendMessage(gw->urlbar, WM_CUT, 0, 0);
+ } else if (gw->bw != NULL) {
+ browser_window_key_press(gw->bw, NS_KEY_CUT_SELECTION);
+ }
+ break;
+
+ case IDM_EDIT_COPY:
+ OpenClipboard(gw->main);
+ EmptyClipboard();
+ CloseClipboard();
+ if (GetFocus() == gw->urlbar) {
+ SendMessage(gw->urlbar, WM_COPY, 0, 0);
+ } else if (gw->bw != NULL) {
+ browser_window_key_press(gw->bw, NS_KEY_COPY_SELECTION);
+ }
+ break;
+
+ case IDM_EDIT_PASTE: {
+ OpenClipboard(gw->main);
+ HANDLE h = GetClipboardData(CF_TEXT);
+ if (h != NULL) {
+ char *content = GlobalLock(h);
+ LOG("pasting %s\n", content);
+ GlobalUnlock(h);
+ }
+ CloseClipboard();
+ if (GetFocus() == gw->urlbar)
+ SendMessage(gw->urlbar, WM_PASTE, 0, 0);
+ else
+ browser_window_key_press(gw->bw, NS_KEY_PASTE);
+ break;
+ }
+
+ case IDM_EDIT_DELETE:
+ if (GetFocus() == gw->urlbar)
+ SendMessage(gw->urlbar, WM_CUT, 0, 0);
+ else
+ browser_window_key_press(gw->bw, NS_KEY_DELETE_RIGHT);
+ break;
+
+ case IDM_EDIT_SELECT_ALL:
+ if (GetFocus() == gw->urlbar)
+ SendMessage(gw->urlbar, EM_SETSEL, 0, -1);
+ else
+ browser_window_key_press(gw->bw, NS_KEY_SELECT_ALL);
+ break;
+
+ case IDM_EDIT_SEARCH:
+ break;
+
+ case IDM_EDIT_PREFERENCES:
+ nsws_prefs_dialog_init(hInstance, gw->main);
+ break;
+
+ case IDM_NAV_BACK:
+ if ((gw->bw != NULL) &&
+ (browser_window_history_back_available(gw->bw))) {
+ browser_window_history_back(gw->bw, false);
+ }
+ nsws_window_update_forward_back(gw);
+ break;
+
+ case IDM_NAV_FORWARD:
+ if ((gw->bw != NULL) &&
+ (browser_window_history_forward_available(gw->bw))) {
+ browser_window_history_forward(gw->bw, false);
+ }
+ nsws_window_update_forward_back(gw);
+ break;
+
+ case IDM_NAV_HOME:
+ {
+ nsurl *url;
+
+ if (nsurl_create(nsoption_charp(homepage_url), &url) != NSERROR_OK) {
+ win32_warning("NoMemory", 0);
+ } else {
+ browser_window_navigate(gw->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ break;
+ }
+
+ case IDM_NAV_STOP:
+ browser_window_stop(gw->bw);
+ break;
+
+ case IDM_NAV_RELOAD:
+ browser_window_reload(gw->bw, true);
+ break;
+
+ case IDM_NAV_LOCALHISTORY:
+ gw->localhistory = nsws_window_create_localhistory(gw);
+ break;
+
+ case IDM_NAV_GLOBALHISTORY:
+ break;
+
+ case IDM_VIEW_ZOOMPLUS: {
+ int x, y;
+ win32_window_get_scroll(gw, &x, &y);
+ if (gw->bw != NULL) {
+ nsws_set_scale(gw, gw->scale * 1.1);
+ }
+ win32_window_redraw_window(gw);
+ win32_window_set_scroll(gw, x, y);
+ break;
+ }
+
+ case IDM_VIEW_ZOOMMINUS: {
+ int x, y;
+ win32_window_get_scroll(gw, &x, &y);
+ if (gw->bw != NULL) {
+ nsws_set_scale(gw, gw->scale * 0.9);
+ }
+ win32_window_redraw_window(gw);
+ win32_window_set_scroll(gw, x, y);
+ break;
+ }
+
+ case IDM_VIEW_ZOOMNORMAL: {
+ int x, y;
+ win32_window_get_scroll(gw, &x, &y);
+ if (gw->bw != NULL) {
+ nsws_set_scale(gw, 1.0);
+ }
+ win32_window_redraw_window(gw);
+ win32_window_set_scroll(gw, x, y);
+ break;
+ }
+
+ case IDM_VIEW_SOURCE:
+ break;
+
+ case IDM_VIEW_SAVE_WIN_METRICS: {
+ RECT r;
+ GetWindowRect(gw->main, &r);
+ nsoption_set_int(window_x, r.left);
+ 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, NULL, NULL);
+ break;
+ }
+
+ case IDM_VIEW_FULLSCREEN: {
+ RECT rdesk;
+ if (gw->fullscreen == NULL) {
+ HWND desktop = GetDesktopWindow();
+ gw->fullscreen = malloc(sizeof(RECT));
+ if ((desktop == NULL) ||
+ (gw->fullscreen == NULL)) {
+ win32_warning("NoMemory", 0);
+ break;
+ }
+ GetWindowRect(desktop, &rdesk);
+ GetWindowRect(gw->main, gw->fullscreen);
+ DeleteObject(desktop);
+ SetWindowLong(gw->main, GWL_STYLE, 0);
+ SetWindowPos(gw->main, HWND_TOPMOST, 0, 0,
+ rdesk.right - rdesk.left,
+ rdesk.bottom - rdesk.top,
+ SWP_SHOWWINDOW);
+ } else {
+ SetWindowLong(gw->main, GWL_STYLE,
+ WS_OVERLAPPEDWINDOW |
+ WS_HSCROLL | WS_VSCROLL |
+ WS_CLIPCHILDREN |
+ WS_CLIPSIBLINGS | CS_DBLCLKS);
+ SetWindowPos(gw->main, HWND_TOPMOST,
+ gw->fullscreen->left,
+ gw->fullscreen->top,
+ gw->fullscreen->right -
+ gw->fullscreen->left,
+ gw->fullscreen->bottom -
+ gw->fullscreen->top,
+ SWP_SHOWWINDOW | SWP_FRAMECHANGED);
+ free(gw->fullscreen);
+ gw->fullscreen = NULL;
+ }
+ break;
+ }
+
+ case IDM_VIEW_DOWNLOADS:
+ break;
+
+ case IDM_VIEW_TOGGLE_DEBUG_RENDERING:
+ if (gw->bw != NULL) {
+ browser_window_debug(gw->bw, CONTENT_DEBUG_REDRAW);
+ /* TODO: This should only redraw, not reformat.
+ * (Layout doesn't change, so reformat is a waste of time) */
+ browser_window_reformat(gw->bw, false, gw->width, gw->height);
+ }
+ break;
+
+ case IDM_VIEW_DEBUGGING_SAVE_BOXTREE:
+ break;
+
+ case IDM_VIEW_DEBUGGING_SAVE_DOMTREE:
+ break;
+
+ case IDM_HELP_CONTENTS:
+ nsws_window_go(hwnd,
+ "http://www.netsurf-browser.org/documentation/");
+ break;
+
+ case IDM_HELP_GUIDE:
+ nsws_window_go(hwnd,
+ "http://www.netsurf-browser.org/documentation/guide");
+ break;
+
+ case IDM_HELP_INFO:
+ nsws_window_go(hwnd,
+ "http://www.netsurf-browser.org/documentation/info");
+ break;
+
+ case IDM_HELP_ABOUT:
+ nsws_about_dialog_init(hInstance, gw->main);
+ break;
+
+ case IDC_MAIN_LAUNCH_URL:
+ {
+ nsurl *url;
+
+ if (GetFocus() != gw->urlbar)
+ break;
+
+ int len = SendMessage(gw->urlbar, WM_GETTEXTLENGTH, 0, 0);
+ char addr[len + 1];
+ SendMessage(gw->urlbar, WM_GETTEXT, (WPARAM)(len + 1), (LPARAM)addr);
+ LOG("launching %s\n", addr);
+
+ if (nsurl_create(addr, &url) != NSERROR_OK) {
+ win32_warning("NoMemory", 0);
+ } else {
+ browser_window_navigate(gw->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+
+ break;
+ }
+
+
+ default:
+ return 1; /* unhandled */
+
+ }
+ return 0; /* control message handled */
+}
+
+
+static LRESULT
+nsws_window_resize(struct gui_window *gw,
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ int x, y;
+ RECT rstatus, rtool;
+
+ if ((gw->toolbar == NULL) ||
+ (gw->urlbar == NULL) ||
+ (gw->statusbar == NULL))
+ return 0;
+
+ SendMessage(gw->statusbar, WM_SIZE, wparam, lparam);
+ SendMessage(gw->toolbar, WM_SIZE, wparam, lparam);
+
+ GetClientRect(gw->toolbar, &rtool);
+ GetWindowRect(gw->statusbar, &rstatus);
+ win32_window_get_scroll(gw, &x, &y);
+ gw->width = LOWORD(lparam);
+ gw->height = HIWORD(lparam) - (rtool.bottom - rtool.top) - (rstatus.bottom - rstatus.top);
+
+ if (gw->drawingarea != NULL) {
+ MoveWindow(gw->drawingarea,
+ 0,
+ rtool.bottom,
+ gw->width,
+ gw->height,
+ true);
+ }
+ nsws_window_update_forward_back(gw);
+
+ win32_window_set_scroll(gw, x, y);
+
+ if (gw->toolbar != NULL) {
+ SendMessage(gw->toolbar, TB_SETSTATE,
+ (WPARAM) IDM_NAV_STOP,
+ MAKELONG(TBSTATE_INDETERMINATE, 0));
+ }
+
+ return 0;
+}
+
+
+/**
+ * callback for window events generally
+ */
+static LRESULT CALLBACK
+nsws_window_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ struct gui_window *gw;
+ RECT rmain;
+
+ LOG_WIN_MSG(hwnd, msg, wparam, lparam);
+
+ /* deal with window creation as a special case */
+ if (msg == WM_CREATE) {
+ /* To cause all the component child windows to be
+ * re-sized correctly a WM_SIZE message of the actual
+ * created size must be sent.
+ *
+ * The message must be posted here because the actual
+ * size values of the component windows are not known
+ * until after the WM_CREATE message is dispatched.
+ */
+ GetClientRect(hwnd, &rmain);
+ PostMessage(hwnd, WM_SIZE, 0, MAKELPARAM(rmain.right, rmain.bottom));
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+
+ gw = nsws_get_gui_window(hwnd);
+ if (gw == NULL) {
+ LOG("Unable to find gui window structure for hwnd %p", hwnd);
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ switch (msg) {
+
+ case WM_CONTEXTMENU:
+ if (nsws_ctx_menu(gw, hwnd, GET_X_LPARAM(lparam),
+ GET_Y_LPARAM(lparam))) {
+ return 0;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (nsws_window_command(hwnd, gw, HIWORD(wparam),
+ LOWORD(wparam), (HWND)lparam) == 0) {
+ return 0;
+ }
+ break;
+
+ case WM_SIZE:
+ return nsws_window_resize(gw, hwnd, wparam, lparam);
+
+ case WM_NCDESTROY:
+ RemoveProp(hwnd, TEXT("GuiWnd"));
+ browser_window_destroy(gw->bw);
+ if (--open_windows <= 0) {
+ win32_set_quit(true);
+ }
+ break;
+
+ }
+
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+
+/**
+ * Create the main window class.
+ */
+nserror
+nsws_create_main_class(HINSTANCE hinstance) {
+ nserror ret = NSERROR_OK;
+ WNDCLASSEX w;
+
+ /* main window */
+ w.cbSize = sizeof(WNDCLASSEX);
+ w.style = 0;
+ w.lpfnWndProc = nsws_window_event_callback;
+ w.cbClsExtra = 0;
+ w.cbWndExtra = 0;
+ w.hInstance = hinstance;
+ w.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
+ w.hCursor = NULL;
+ w.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
+ w.lpszMenuName = NULL;
+ w.lpszClassName = windowclassname_main;
+ w.hIconSm = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
+
+ if (RegisterClassEx(&w) == 0) {
+ win_perror("DrawableClass");
+ ret = NSERROR_INIT_FAILED;
+ }
+
+ hInstance = hinstance;
+
+ return ret;
+}
+
+
+
+
+
+
+/**
+ * create a new gui_window to contain a browser_window.
+ *
+ * \param bw the browser_window to connect to the new gui_window
+ * \param existing An existing window.
+ * \param flags The flags controlling the construction.
+ * \return The new win32 gui window or NULL on error.
+ */
+static struct gui_window *
+win32_window_create(struct browser_window *bw,
+ struct gui_window *existing,
+ gui_window_create_flags flags)
+{
+ struct gui_window *gw;
+
+ LOG("Creating gui window for browser window %p", bw);
+
+ gw = calloc(1, sizeof(struct gui_window));
+
+ if (gw == NULL) {
+ return NULL;
+ }
+
+ /* connect gui window to browser window */
+ gw->bw = bw;
+
+ gw->width = 800;
+ gw->height = 600;
+ gw->scale = 1.0;
+ gw->toolbuttonsize = 24;
+ gw->requestscrollx = 0;
+ gw->requestscrolly = 0;
+ gw->localhistory = NULL;
+
+ gw->mouse = malloc(sizeof(struct browser_mouse));
+ if (gw->mouse == NULL) {
+ free(gw);
+ LOG("Unable to allocate mouse state");
+ return NULL;
+ }
+ gw->mouse->gui = gw;
+ gw->mouse->state = 0;
+ gw->mouse->pressed_x = 0;
+ gw->mouse->pressed_y = 0;
+
+ /* add window to list */
+ if (window_list != NULL)
+ window_list->prev = gw;
+ gw->next = window_list;
+ window_list = gw;
+
+ gw->main = nsws_window_create(gw);
+ gw->toolbar = nsws_window_create_toolbar(gw, gw->main);
+ gw->statusbar = nsws_window_create_statusbar(gw);
+ gw->drawingarea = nsws_window_create_drawable(hInstance, gw->main, gw);
+
+ LOG("new window: main:%p toolbar:%p statusbar %p drawingarea %p", gw->main, gw->toolbar, gw->statusbar, gw->drawingarea);
+
+ font_hwnd = gw->drawingarea;
+ open_windows++;
+ ShowWindow(gw->main, SW_SHOWNORMAL);
+
+ return gw;
+}
+
+
+/**
+ * window cleanup code
+ */
+static void win32_window_destroy(struct gui_window *w)
+{
+ if (w == NULL)
+ return;
+
+ if (w->prev != NULL)
+ w->prev->next = w->next;
+ else
+ window_list = w->next;
+
+ if (w->next != NULL)
+ w->next->prev = w->prev;
+
+ DestroyAcceleratorTable(w->acceltable);
+
+ free(w);
+ w = NULL;
+}
+
+
+
+
+static void
+win32_window_update_box(struct gui_window *gw, const struct rect *rect)
+{
+ /* LOG("gw:%p %f,%f %f,%f", gw, data->redraw.x, data->redraw.y, data->redraw.width, data->redraw.height); */
+
+ if (gw == NULL)
+ return;
+
+ RECT redrawrect;
+
+ redrawrect.left = (long)rect->x0 - (gw->scrollx / gw->scale);
+ redrawrect.top = (long)rect->y0 - (gw->scrolly / gw->scale);
+ redrawrect.right =(long)rect->x1;
+ redrawrect.bottom = (long)rect->y1;
+
+ RedrawWindow(gw->drawingarea, &redrawrect, NULL,
+ RDW_INVALIDATE | RDW_NOERASE);
+
+}
+
+
+
+
+
+static void win32_window_get_dimensions(struct gui_window *gw, int *width, int *height,
+ bool scaled)
+{
+ if (gw == NULL)
+ return;
+
+ LOG("get dimensions %p w=%d h=%d", gw, gw->width, gw->height);
+
+ *width = gw->width;
+ *height = gw->height;
+}
+
+static void win32_window_update_extent(struct gui_window *w)
+{
+
+}
+
+/**
+ * callback from core to reformat a window.
+ *
+ * \param gw The win32 gui window to reformat.
+ */
+static void win32_window_reformat(struct gui_window *gw)
+{
+ if (gw != NULL) {
+ browser_window_reformat(gw->bw, false, gw->width, gw->height);
+ }
+}
+
+
+/**
+ * set window title
+ *
+ * \param w the Windows gui window.
+ * \param title to set on window
+ */
+static void win32_window_set_title(struct gui_window *w, const char *title)
+{
+ if (w == NULL)
+ return;
+ LOG("%p, title %s", w, title);
+ char *fulltitle = malloc(strlen(title) +
+ SLEN(" - NetSurf") + 1);
+ if (fulltitle == NULL) {
+ win32_warning("NoMemory", 0);
+ return;
+ }
+ strcpy(fulltitle, title);
+ strcat(fulltitle, " - NetSurf");
+ SendMessage(w->main, WM_SETTEXT, 0, (LPARAM)fulltitle);
+ free(fulltitle);
+}
+
+
+static nserror win32_window_set_url(struct gui_window *w, nsurl *url)
+{
+ SendMessage(w->urlbar, WM_SETTEXT, 0, (LPARAM) nsurl_access(url));
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * set the status bar message
+ */
+static void win32_window_set_status(struct gui_window *w, const char *text)
+{
+ if (w == NULL)
+ return;
+ SendMessage(w->statusbar, WM_SETTEXT, 0, (LPARAM)text);
+}
+
+
+/**
+ * set the pointer shape
+ */
+static void win32_window_set_pointer(struct gui_window *w,
+ gui_pointer_shape shape)
+{
+ SetCursor(nsws_get_pointer(shape));
+}
+
+
+/**
+ * place caret in window
+ */
+static void win32_window_place_caret(struct gui_window *w, int x, int y,
+ int height, const struct rect *clip)
+{
+ if (w == NULL)
+ return;
+ CreateCaret(w->drawingarea, (HBITMAP)NULL, 1, height * w->scale);
+ SetCaretPos(x * w->scale - w->scrollx,
+ y * w->scale - w->scrolly);
+ ShowCaret(w->drawingarea);
+}
+
+/**
+ * clear window caret
+ */
+static void win32_window_remove_caret(struct gui_window *w)
+{
+ if (w == NULL)
+ return;
+ HideCaret(w->drawingarea);
+}
+
+
+
+
+static void win32_window_start_throbber(struct gui_window *w)
+{
+ if (w == NULL)
+ return;
+ nsws_window_update_forward_back(w);
+
+ if (w->mainmenu != NULL) {
+ EnableMenuItem(w->mainmenu, IDM_NAV_STOP, MF_ENABLED);
+ EnableMenuItem(w->mainmenu, IDM_NAV_RELOAD, MF_GRAYED);
+ }
+ if (w->rclick != NULL) {
+ EnableMenuItem(w->rclick, IDM_NAV_STOP, MF_ENABLED);
+ EnableMenuItem(w->rclick, IDM_NAV_RELOAD, MF_GRAYED);
+ }
+ if (w->toolbar != NULL) {
+ SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) IDM_NAV_STOP,
+ MAKELONG(TBSTATE_ENABLED, 0));
+ SendMessage(w->toolbar, TB_SETSTATE,
+ (WPARAM) IDM_NAV_RELOAD,
+ MAKELONG(TBSTATE_INDETERMINATE, 0));
+ }
+ w->throbbing = true;
+ Animate_Play(w->throbber, 0, -1, -1);
+}
+
+
+
+static void win32_window_stop_throbber(struct gui_window *w)
+{
+ if (w == NULL)
+ return;
+
+ nsws_window_update_forward_back(w);
+ if (w->mainmenu != NULL) {
+ EnableMenuItem(w->mainmenu, IDM_NAV_STOP, MF_GRAYED);
+ EnableMenuItem(w->mainmenu, IDM_NAV_RELOAD, MF_ENABLED);
+ }
+
+ if (w->rclick != NULL) {
+ EnableMenuItem(w->rclick, IDM_NAV_STOP, MF_GRAYED);
+ EnableMenuItem(w->rclick, IDM_NAV_RELOAD, MF_ENABLED);
+ }
+
+ if (w->toolbar != NULL) {
+ SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) IDM_NAV_STOP,
+ MAKELONG(TBSTATE_INDETERMINATE, 0));
+ SendMessage(w->toolbar, TB_SETSTATE,
+ (WPARAM) IDM_NAV_RELOAD,
+ MAKELONG(TBSTATE_ENABLED, 0));
+ }
+
+ w->throbbing = false;
+ Animate_Stop(w->throbber);
+ Animate_Seek(w->throbber, 0);
+}
+
+static struct gui_window_table window_table = {
+ .create = win32_window_create,
+ .destroy = win32_window_destroy,
+ .redraw = win32_window_redraw_window,
+ .update = win32_window_update_box,
+ .get_scroll = win32_window_get_scroll,
+ .set_scroll = win32_window_set_scroll,
+ .get_dimensions = win32_window_get_dimensions,
+ .update_extent = win32_window_update_extent,
+ .reformat = win32_window_reformat,
+
+ .set_title = win32_window_set_title,
+ .set_url = win32_window_set_url,
+ .set_status = win32_window_set_status,
+ .set_pointer = win32_window_set_pointer,
+ .place_caret = win32_window_place_caret,
+ .remove_caret = win32_window_remove_caret,
+ .start_throbber = win32_window_start_throbber,
+ .stop_throbber = win32_window_stop_throbber,
+};
+
+struct gui_window_table *win32_window_table = &window_table;
+
+/* exported interface documented in windows/window.h */
+struct gui_window *nsws_get_gui_window(HWND hwnd)
+{
+ struct gui_window *gw = NULL;
+ HWND phwnd = hwnd;
+
+ /* scan the window hierachy for gui window */
+ while (phwnd != NULL) {
+ gw = GetProp(phwnd, TEXT("GuiWnd"));
+ if (gw != NULL)
+ break;
+ phwnd = GetParent(phwnd);
+ }
+
+ if (gw == NULL) {
+ /* try again looking for owner windows instead */
+ phwnd = hwnd;
+ while (phwnd != NULL) {
+ gw = GetProp(phwnd, TEXT("GuiWnd"));
+ if (gw != NULL)
+ break;
+ phwnd = GetWindow(phwnd, GW_OWNER);
+ }
+ }
+
+ return gw;
+}
+
+
+/* exported interface documented in windows/window.h */
+bool nsws_window_go(HWND hwnd, const char *urltxt)
+{
+ struct gui_window *gw;
+ nsurl *url;
+
+ gw = nsws_get_gui_window(hwnd);
+ if (gw == NULL)
+ return false;
+
+ if (nsurl_create(urltxt, &url) != NSERROR_OK) {
+ win32_warning("NoMemory", 0);
+ } else {
+ browser_window_navigate(gw->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+
+ return true;
+}
+
+
+/* exported interface documented in windows/window.h */
+HWND gui_window_main_window(struct gui_window *w)
+{
+ if (w == NULL)
+ return NULL;
+ return w->main;
+}
+
+
+/* exported interface documented in windows/window.h */
+struct nsws_localhistory *gui_window_localhistory(struct gui_window *w)
+{
+ if (w == NULL)
+ return NULL;
+ return w->localhistory;
+}
diff --git a/frontends/windows/window.h b/frontends/windows/window.h
new file mode 100644
index 000000000..ec54287f4
--- /dev/null
+++ b/frontends/windows/window.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * 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/>.
+ */
+
+#ifndef _NETSURF_WINDOWS_WINDOW_H_
+#define _NETSURF_WINDOWS_WINDOW_H_
+
+/** The window operation function table for win32 */
+extern struct gui_window_table *win32_window_table;
+
+#include "desktop/mouse.h"
+
+struct browser_mouse {
+ struct gui_window *gui;
+ struct box *box;
+
+ double pressed_x;
+ double pressed_y;
+ bool waiting;
+ browser_mouse_state state;
+};
+
+struct gui_window {
+ /* The front's private data connected to a browser window */
+ /* currently 1<->1 gui_window<->windows window [non-tabbed] */
+ struct browser_window *bw; /** the browser_window */
+
+ HWND main; /**< handle to the actual window */
+ HWND toolbar; /**< toolbar handle */
+ HWND urlbar; /**< url bar handle */
+ HWND throbber; /** throbber handle */
+ HWND drawingarea; /**< drawing area handle */
+ HWND statusbar; /**< status bar handle */
+ HWND vscroll; /**< vertical scrollbar handle */
+ HWND hscroll; /**< horizontal scrollbar handle */
+
+ HMENU mainmenu; /**< the main menu */
+ HMENU rclick; /**< the right-click menu */
+ struct nsws_localhistory *localhistory; /**< handle to local history window */
+ int width; /**< width of window */
+ int height; /**< height of drawing area */
+
+ int toolbuttonc; /**< number of toolbar buttons */
+ int toolbuttonsize; /**< width, height of buttons */
+ bool throbbing; /**< whether currently throbbing */
+
+ struct browser_mouse *mouse; /**< mouse state */
+
+ HACCEL acceltable; /**< accelerators */
+
+ float scale; /**< scale of content */
+
+ int scrollx; /**< current scroll location */
+ int scrolly; /**< current scroll location */
+
+ RECT *fullscreen; /**< memorize non-fullscreen area */
+ RECT redraw; /**< Area needing redraw. */
+ int requestscrollx, requestscrolly; /**< scolling requested. */
+ struct gui_window *next, *prev; /**< global linked list */
+};
+
+
+/**
+ * Obtain gui window structure from window handle.
+ *
+ * \param hwnd The window handle.
+ * \return The gui window associated with the window handle.
+ */
+struct gui_window *nsws_get_gui_window(HWND hwnd);
+
+/**
+ * Cause a browser window to navigate to a url
+ *
+ * \param hwnd The win32 handle to the browser window or one of its decendants.
+ * \param urltxt The URL to navigate to.
+ */
+bool nsws_window_go(HWND hwnd, const char *urltxt);
+
+void win32_window_set_scroll(struct gui_window *w, int sx, int sy);
+
+nserror nsws_create_main_class(HINSTANCE hinstance);
+
+/**
+ * Get the main win32 window handle from a gui window
+ */
+HWND gui_window_main_window(struct gui_window *);
+
+
+/**
+ * Get the localhistory win32 window handle from a gui window
+ */
+struct nsws_localhistory *gui_window_localhistory(struct gui_window *);
+
+
+#endif /* _NETSURF_WINDOWS_WINDOW_H_ */