summaryrefslogtreecommitdiff
path: root/frontends/windows/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/windows/window.c')
-rw-r--r--frontends/windows/window.c1741
1 files changed, 1741 insertions, 0 deletions
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;
+}