/* * Copyright 2008 Vincent Sanders * Copyright 2009 Mark Benjamin * * 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 . */ #include #include #include #include #include #include #include #include #include #define _WIN32_IE (0x0501) #include #include #include "content/urldb.h" #include "content/fetch.h" #include "css/utils.h" #include "desktop/gui.h" #include "desktop/history_core.h" #include "desktop/plotters.h" #include "desktop/netsurf.h" #include "desktop/options.h" #include "desktop/save_complete.h" #include "desktop/selection.h" #include "desktop/textinput.h" #include "render/html.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" #include "windows/about.h" #include "windows/gui.h" #include "windows/findfile.h" #include "windows/font.h" #include "windows/localhistory.h" #include "windows/plot.h" #include "windows/prefs.h" #include "windows/resourceid.h" char *default_stylesheet_url; char *adblock_stylesheet_url; char *quirks_stylesheet_url; char *options_file_location; struct gui_window *input_window = NULL; struct gui_window *search_current_window; struct gui_window *window_list = NULL; FARPROC urlproc; FARPROC toolproc; static char default_page[] = "http://www.netsurf-browser.org/welcome/"; static HICON hIcon, hIconS; static int open_windows = 0; #define NTOOLBUTTONS 5 #define NSWS_THROBBER_WIDTH 24 #define NSWS_URL_ENTER (WM_USER) 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 */ HDC bufferdc; /**< the screen buffer */ HBITMAP bufferbm; /**< the buffer bitmap */ struct nsws_localhistory *localhistory; /**< handle to local history window */ int width; /**< width of window */ int height; /**< height of drawing area */ int urlbarwidth; /**< width of url bar */ int ntoolbuttons; /**< number of toolbar buttons */ int toolbuttondimension; /**< width, height of buttons */ int voffset; /**< height of toolbar */ bool throbbing; /**< whether currently throbbing */ TBBUTTON buttons[NTOOLBUTTONS + 1]; /* 1 = url bar */ HBITMAP hbmp[NTOOLBUTTONS]; /**< tool button images */ 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. */ RECT clip; /**< current clip rectangle */ int requestscrollx, requestscrolly; /**< scolling requested. */ struct gui_window *next, *prev; /**< global linked list */ }; static struct nsws_pointers nsws_pointer; #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif typedef enum { NSWS_ID_TOOLBAR = 1111, NSWS_ID_URLBAR, NSWS_ID_THROBBER, NSWS_ID_DRAWINGAREA, NSWS_ID_STATUSBAR, NSWS_ID_LAUNCH_URL, } nsws_constants ; LRESULT CALLBACK nsws_window_url_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); LRESULT CALLBACK nsws_window_toolbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); LRESULT CALLBACK nsws_window_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); HINSTANCE hinstance; void gui_multitask(void) { /* LOG(("gui_multitask")); */ } /** * called synchronously to handle all redraw events */ static void redraw(void) { struct gui_window *w = window_list; struct browser_window *bw; struct content *c; HDC hdc; while (w != NULL) { if ((w->redraw.right - w->redraw.left <= 0) || (w->redraw.bottom - w->redraw.top <= 0)) { w = w->next; continue; } bw = w->bw; if (bw == NULL) { w = w->next; continue; } c = bw->current_content; if ((c == NULL) || (c->locked)) { w = w->next; continue; } current_hwnd = w->main; PostMessage(w->toolbar, WM_PAINT, 0, 0); PostMessage(w->urlbar, WM_PAINT, 0, 0); w->scrolly += w->requestscrolly; w->scrollx += w->requestscrollx; w->scrolly = MAX(w->scrolly, 0); w->scrolly = MIN(w->scrolly, c->height * w->bw->scale - w->height); w->scrollx = MAX(w->scrollx, 0); w->scrollx = MIN(w->scrollx, c->width * w->bw->scale - w->width); /* redraw */ /* w->redraw.left = MIN(w->redraw.left, w->scrollx); w->redraw.top = MIN(w->redraw.top, w->scrolly + w->voffset ); w->redraw.right = MAX(w->redraw.right, w->scrollx + w->width); w->redraw.bottom = MAX(w->redraw.bottom, w->scrolly + w->height + w->voffset ); */ current_redraw_browser = bw; nsws_plot_set_scale(bw->scale); /* doublebuffering = true; */ hdc = GetDC(w->main); if (w->bufferbm == NULL) { w->bufferbm = CreateCompatibleBitmap(hdc, w->width, w->height + w->voffset); SelectObject(w->bufferdc, w->bufferbm); } if ((w->bufferbm == NULL) || (w->bufferdc == NULL) || (hdc == NULL)) doublebuffering = false; if (doublebuffering) bufferdc = w->bufferdc; content_redraw(c, -w->scrollx / w->bw->scale, -w->scrolly / w->bw->scale, w->width, w->height, w->redraw.left - w->scrollx / w->bw->scale, w->redraw.top - w->scrolly / w->bw->scale, w->redraw.right - w->scrollx / w->bw->scale, w->redraw.bottom - w->scrolly / w->bw->scale, bw->scale, 0xFFFFFF); if (doublebuffering) /* blit buffer to screen */ BitBlt(hdc, 0, w->voffset, w->width, w->height, w->bufferdc, 0, w->voffset, SRCCOPY); ReleaseDC(w->main, hdc); doublebuffering = false; w->requestscrolly = 0; w->requestscrollx = 0; w->redraw.left = w->redraw.top = INT_MAX; w->redraw.right = w->redraw.bottom = -(INT_MAX); w = w->next; } } void gui_poll(bool active) { MSG Msg; if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) { if (!((current_gui == NULL) || (TranslateAccelerator(current_gui->main, current_gui->acceltable, &Msg)))) TranslateMessage(&Msg); DispatchMessage(&Msg); } schedule_run(); } /** * callback for url bar events */ LRESULT CALLBACK nsws_window_url_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { DWORD i, ii; SendMessage(hwnd, EM_GETSEL, (WPARAM)&i, (LPARAM)&ii); int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if (msg == WM_PAINT) { SendMessage(hwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); SendMessage(hwnd, EM_SETSEL, (WPARAM)i, (LPARAM)ii); } return CallWindowProc((WNDPROC) urlproc, hwnd, msg, wparam, lparam); } /** * callback for toolbar events */ LRESULT CALLBACK nsws_window_toolbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { bool match = false; struct gui_window *w = window_list; while (w != NULL) { if (w->toolbar == hwnd) { match = true; break; } w = w->next; } if (match == false) { /* during initial window creation */ w = window_list; while (w != NULL) { if (w->toolbar == NULL) { w->toolbar = hwnd; break; } w = w->next; } } if ((msg == WM_LBUTTONUP) || (msg == WM_LBUTTONDOWN) || (msg == WM_MOUSEMOVE)) { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w != NULL) && (x > w->ntoolbuttons * w->toolbuttondimension) && (y < w->voffset)) { if (msg == WM_LBUTTONDOWN) SetFocus(w->urlbar); return CallWindowProc((WNDPROC) nsws_window_url_callback, w->urlbar, msg, wparam, MAKELONG(x - w->ntoolbuttons * w->toolbuttondimension, y)); } } return CallWindowProc((WNDPROC) toolproc, hwnd, msg, wparam, lparam); } /** * 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 = history_forward_available(w->bw->history); bool back = history_back_available(w->bw->history); if (w->mainmenu != NULL) { EnableMenuItem(w->mainmenu, NSWS_ID_NAV_FORWARD, (forward ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->mainmenu, NSWS_ID_NAV_BACK, (back ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->rclick, NSWS_ID_NAV_FORWARD, (forward ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->rclick, NSWS_ID_NAV_BACK, (back ? MF_ENABLED : MF_GRAYED)); } if (w->toolbar != NULL) { SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_FORWARD, MAKELONG((forward ? TBSTATE_ENABLED : TBSTATE_INDETERMINATE), 0)); SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_BACK, MAKELONG((back ? TBSTATE_ENABLED : TBSTATE_INDETERMINATE), 0)); } } static void nsws_update_edit(struct gui_window *w) { bool paste, copy, del; 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 ((w->bw != NULL) && (w->bw->sel != NULL)){ paste = (w->bw->paste_callback != NULL); copy = w->bw->sel->defined; del = ((w->bw->sel->defined) && (w->bw->caret_callback != NULL)); } else { paste = false; copy = false; del = false; } EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_PASTE, (paste ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->rclick, NSWS_ID_EDIT_PASTE, (paste ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_COPY, (copy ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(w->rclick, NSWS_ID_EDIT_COPY, (copy ? MF_ENABLED : MF_GRAYED)); if (del == true) { EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_CUT, MF_ENABLED); EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_DELETE, MF_ENABLED); EnableMenuItem(w->rclick, NSWS_ID_EDIT_CUT, MF_ENABLED); EnableMenuItem(w->rclick, NSWS_ID_EDIT_DELETE, MF_ENABLED); } else { EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_CUT, MF_GRAYED); EnableMenuItem(w->mainmenu, NSWS_ID_EDIT_DELETE, MF_GRAYED); EnableMenuItem(w->rclick, NSWS_ID_EDIT_CUT, MF_GRAYED); EnableMenuItem(w->rclick, NSWS_ID_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; } /** * 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 = NSWS_ID_FILE_QUIT; accels[1].key = 0x4E; /* N */ accels[1].cmd = NSWS_ID_FILE_OPEN_WINDOW; accels[2].key = VK_LEFT; accels[2].cmd = NSWS_ID_NAV_BACK; accels[3].key = VK_RIGHT; accels[3].cmd = NSWS_ID_NAV_FORWARD; accels[4].key = VK_UP; accels[4].cmd = NSWS_ID_NAV_HOME; accels[5].key = VK_BACK; accels[5].cmd = NSWS_ID_NAV_STOP; accels[6].key = VK_SPACE; accels[6].cmd = NSWS_ID_NAV_RELOAD; accels[7].key = 0x4C; /* L */ accels[7].cmd = NSWS_ID_FILE_OPEN_LOCATION; accels[8].key = 0x57; /* w */ accels[8].cmd = NSWS_ID_FILE_CLOSE_WINDOW; accels[9].key = 0x41; /* A */ accels[9].cmd = NSWS_ID_EDIT_SELECT_ALL; accels[10].key = VK_F8; accels[10].cmd = NSWS_ID_VIEW_SOURCE; accels[11].key = VK_RETURN; accels[11].fVirt = FVIRTKEY; accels[11].cmd = NSWS_ID_LAUNCH_URL; accels[12].key = VK_F11; accels[12].fVirt = FVIRTKEY; accels[12].cmd = NSWS_ID_VIEW_FULLSCREEN; w->acceltable = CreateAcceleratorTable(accels, nitems); } /** * set window icons */ static void nsws_window_set_ico(struct gui_window *w) { char ico[PATH_MAX]; nsws_find_resource(ico, "NetSurf32.ico", "windows/res/NetSurf32.ico"); LOG(("setting ico as %s", ico)); hIcon = LoadImage(NULL, ico, IMAGE_ICON, 32, 32, LR_LOADFROMFILE); if (hIcon != NULL) SendMessage(w->main, WM_SETICON, ICON_BIG, (LPARAM) hIcon); nsws_find_resource(ico, "NetSurf16.ico", "windows/res/NetSurf16.ico"); LOG(("setting ico as %s", ico)); hIconS = LoadImage(NULL, ico, IMAGE_ICON, 16, 16, LR_LOADFROMFILE); if (hIconS != NULL) SendMessage(w->main, WM_SETICON, ICON_SMALL, (LPARAM)hIconS); } /** * creation of url bar */ static void nsws_window_urlbar_create(struct gui_window *w) { HWND hwnd = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_OEMCONVERT, w->toolbuttondimension * w->ntoolbuttons + 4, 10, w->urlbarwidth - 8, w->toolbuttondimension - 12, w->main, (HMENU) NSWS_ID_URLBAR, hinstance, NULL); /*urlproc = (FARPROC) SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) nsws_window_url_callback);*/ w->urlbar = hwnd; } /** * creation of throbber */ static void 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) NSWS_ID_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); w->throbber = hwnd; } /** * creation of toolbar */ static void nsws_window_toolbar_create(struct gui_window *w) { unsigned int listid = 0; char imagepath[PATH_MAX]; /* NB there is currently an immediate window close at * netsurf launch in real/virtual - as distinct from * emulation - windows whose probable cause is the * location of the url bar to the right of the buttons; * really the way forward would quite possibly be to * implement an active bitmap as the button bar, sensitive * to hover / click events; the immediate window close * behaviour was observed during development when testing * the arrangements of url bar / buttons although much has * changed since then */ HWND hwnd = CreateWindow(TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, w->width, w->toolbuttondimension + 12, w->main, (HMENU) NSWS_ID_TOOLBAR, hinstance, NULL); HIMAGELIST hImageList = ImageList_Create(w->toolbuttondimension - 8, w->toolbuttondimension - 8, 0, w->ntoolbuttons, 0); SendMessage(hwnd, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); ZeroMemory(w->buttons, sizeof(w->buttons)); w->buttons[5].iBitmap = w->urlbarwidth; w->buttons[5].fsStyle = TBSTYLE_SEP; w->buttons[5].iString = -1; /* w->buttons[0].fsState = TBSTATE_ENABLED; */ /* keep bitmaps in cache memory for re-creation of toolbar */ #define MAKE_BUTTON(p, q, r) \ if (w->hbmp[p] == NULL) { \ nsws_find_resource(imagepath, #r ".bmp", "windows/res/" \ #r ".bmp"); \ LOG(("loading toolbutton image %s", imagepath)); \ w->hbmp[p] = LoadImage(NULL, imagepath, IMAGE_BITMAP, \ w->toolbuttondimension - 8, \ w->toolbuttondimension - 8, LR_SHARED | \ LR_LOADFROMFILE | LR_LOADTRANSPARENT); \ } \ ImageList_Add(hImageList, w->hbmp[p], NULL); \ w->buttons[p].iBitmap = MAKELONG(p, 0); \ w->buttons[p].idCommand = NSWS_ID_NAV_##q; \ w->buttons[p].fsState = TBSTATE_ENABLED; \ w->buttons[p].fsStyle = TBSTYLE_BUTTON MAKE_BUTTON(0, BACK, back); MAKE_BUTTON(1, FORWARD, forward); MAKE_BUTTON(2, HOME, home); MAKE_BUTTON(3, STOP, stop); MAKE_BUTTON(4, RELOAD, reload); #undef MAKE_BUTTON SendMessage(hwnd, TB_SETIMAGELIST, (WPARAM) listid, (LPARAM) hImageList); SendMessage(hwnd, TB_ADDBUTTONS, w->ntoolbuttons + 1, (LPARAM) &(w->buttons)); w->toolbar = hwnd; DeleteObject(hImageList); nsws_window_urlbar_create(w); nsws_window_throbber_create(w); SendMessage(hwnd, WM_SIZE, 0, MAKELONG(w->width, w->toolbuttondimension + 12)); toolproc = (FARPROC) SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) nsws_window_toolbar_callback); } /** * creation of status bar */ static void nsws_window_statusbar_create(struct gui_window *w) { HWND hwnd = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, w->main, (HMENU) NSWS_ID_STATUSBAR, hinstance, NULL); SendMessage(hwnd, SB_SETTEXT, 0, (LPARAM)"NetSurf"); w->statusbar = hwnd; } static void nsws_window_drawingarea_create(struct gui_window *w) { /* potentially make drawingarea window from frameless window + scrollbars here */ } /** * creation of vertical scrollbar */ static void nsws_window_vscroll_create(struct gui_window *w) { w->vscroll = CreateWindow("SCROLLBAR", NULL, WS_CHILD | SBS_VERT, 0, 0, CW_USEDEFAULT, 300, w->main, NULL, hinstance, NULL); } /** * creation of horizontal scrollbar */ static void nsws_window_hscroll_create(struct gui_window *w) { w->hscroll = CreateWindow("SCROLLBAR", NULL, WS_CHILD | SBS_HORZ, 0, 0, 200, CW_USEDEFAULT, w->main, NULL, hinstance, NULL); } /** * callback for window events generally */ LRESULT CALLBACK nsws_window_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { bool match = false; bool historyactive = false; struct gui_window *w = window_list; while (w != NULL) { if (w->main == hwnd) { match = true; break; } w = w->next; } if (!match) { /* during initial window creation */ w = window_list; while (w != NULL) { if (w->main == NULL) { w->main = hwnd; break; } w = w->next; } } if ((match) && (current_gui == NULL)) { /* local history window is active */ if ((msg == WM_LBUTTONDOWN) || (msg == WM_PAINT)) historyactive = true; else if ((msg == WM_NCHITTEST) || (msg == WM_SETCURSOR)) return DefWindowProc(hwnd, msg, wparam, lparam); else return 0; } current_gui = w; switch(msg) { case WM_KEYDOWN: { if (GetFocus() != hwnd) break; uint32_t i; bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); bool capslock = ((GetKeyState(VK_CAPITAL) & 1) == 1); switch(wparam) { case VK_LEFT: i = KEY_LEFT; if (shift) SendMessage(hwnd, WM_HSCROLL, MAKELONG(SB_LINELEFT, 0), 0); break; case VK_RIGHT: i = KEY_RIGHT; if (shift) SendMessage(hwnd, WM_HSCROLL, MAKELONG(SB_LINERIGHT, 0), 0); break; case VK_UP: i = KEY_UP; if (shift) SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); break; case VK_DOWN: i = KEY_DOWN; if (shift) SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); break; case VK_HOME: i = KEY_LINE_START; if (shift) SendMessage(hwnd, WM_HSCROLL, MAKELONG(SB_PAGELEFT, 0), 0); break; case VK_END: i = KEY_LINE_END; if (shift) SendMessage(hwnd, WM_HSCROLL, MAKELONG(SB_PAGERIGHT, 0), 0); break; case VK_DELETE: i = 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 (w != NULL) browser_window_key_press(w->bw, i); break; } case WM_MOUSEMOVE: { int x,y; bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); bool ctrl = ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000); bool alt = ((GetKeyState(VK_MENU) & 0x8000) == 0x8000); x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w == NULL) || (w->mouse == NULL) || (w->bw == NULL) || (y < w->voffset)) return DefWindowProc(hwnd, msg, wparam, lparam); if ((w->mouse->state & BROWSER_MOUSE_PRESS_1) != 0) { browser_window_mouse_click(w->bw, BROWSER_MOUSE_DRAG_1, w->mouse->pressed_x, w->mouse->pressed_y); w->mouse->state &= ~BROWSER_MOUSE_PRESS_1; w->mouse->state |= BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_DRAG_ON; } else if ((w->mouse->state & BROWSER_MOUSE_PRESS_2) != 0) { browser_window_mouse_click(w->bw, BROWSER_MOUSE_DRAG_2, w->mouse->pressed_x, w->mouse->pressed_y); w->mouse->state &= ~BROWSER_MOUSE_PRESS_2; w->mouse->state |= BROWSER_MOUSE_HOLDING_2 | BROWSER_MOUSE_DRAG_ON; } if (((w->mouse->state & BROWSER_MOUSE_MOD_1) != 0) && !shift) w->mouse->state &= ~BROWSER_MOUSE_MOD_1; if (((w->mouse->state & BROWSER_MOUSE_MOD_2) != 0) && !ctrl) w->mouse->state &= ~BROWSER_MOUSE_MOD_2; if (((w->mouse->state & BROWSER_MOUSE_MOD_3) != 0) && !alt) w->mouse->state &= ~BROWSER_MOUSE_MOD_3; browser_window_mouse_track(w->bw, w->mouse->state, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_LBUTTONDOWN: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w == NULL) || (w->mouse == NULL) || (w->bw == NULL) || (y < w->voffset)) { nsws_localhistory_close(w); return DefWindowProc(hwnd, msg, wparam, lparam); } w->mouse->state = BROWSER_MOUSE_PRESS_1; if ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_1; if ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_2; if ((GetKeyState(VK_MENU) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_3; w->mouse->pressed_x = (x + w->scrollx) / w->bw->scale; w->mouse->pressed_y = (y - w->voffset + w->scrolly) / w->bw->scale; SetFocus(hwnd); browser_window_mouse_click(w->bw, w->mouse->state, (x + w->scrollx) / w->bw->scale , (y - w->voffset + w->scrolly) / w->bw->scale); nsws_localhistory_close(w); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_RBUTTONDOWN: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w == NULL) || (w->mouse == NULL) || (w->bw == NULL) || (y < w->voffset)) return DefWindowProc(hwnd, msg, wparam, lparam); w->mouse->state = BROWSER_MOUSE_PRESS_2; if ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_1; if ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_2; if ((GetKeyState(VK_MENU) & 0x8000) == 0x8000) w->mouse->state |= BROWSER_MOUSE_MOD_3; w->mouse->pressed_x = (x + w->scrollx) / w->bw->scale; w->mouse->pressed_y = (y - w->voffset + w->scrolly) / w->bw->scale; SetFocus(hwnd); browser_window_mouse_click(w->bw, w->mouse->state, (x + w->scrollx) / w->bw->scale , (y - w->voffset + w->scrolly) / w->bw->scale); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_LBUTTONUP: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w == NULL) || (w->mouse == NULL) || (w->bw == NULL) || (y < w->voffset)) return DefWindowProc(hwnd, msg, wparam, lparam); bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); bool ctrl = ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000); bool alt = ((GetKeyState(VK_MENU) & 0x8000) == 0x8000); if ((w->mouse->state & BROWSER_MOUSE_PRESS_1) != 0) { w->mouse->state &= ~BROWSER_MOUSE_PRESS_1; w->mouse->state |= BROWSER_MOUSE_CLICK_1; } if (((w->mouse->state & BROWSER_MOUSE_MOD_1) != 0) && !shift) w->mouse->state &= ~BROWSER_MOUSE_MOD_1; if (((w->mouse->state & BROWSER_MOUSE_MOD_2) != 0) && !ctrl) w->mouse->state &= ~BROWSER_MOUSE_MOD_2; if (((w->mouse->state & BROWSER_MOUSE_MOD_3) != 0) && !alt) w->mouse->state &= ~BROWSER_MOUSE_MOD_3; if ((w->mouse->state & BROWSER_MOUSE_CLICK_1) != 0) browser_window_mouse_click(w->bw, w->mouse->state, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); else browser_window_mouse_drag_end(w->bw, 0, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); w->mouse->state = 0; return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_RBUTTONUP: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w == NULL) || (w->mouse == NULL) || (w->bw == NULL) || (y < w->voffset)) return DefWindowProc(hwnd, msg, wparam, lparam); bool shift = ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); bool ctrl = ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000); bool alt = ((GetKeyState(VK_MENU) & 0x8000) == 0x8000); if ((w->mouse->state & BROWSER_MOUSE_PRESS_2) != 0) { w->mouse->state &= ~BROWSER_MOUSE_PRESS_2; w->mouse->state |= BROWSER_MOUSE_CLICK_2; } if (((w->mouse->state & BROWSER_MOUSE_MOD_1) != 0) && !shift) w->mouse->state &= ~BROWSER_MOUSE_MOD_1; if (((w->mouse->state & BROWSER_MOUSE_MOD_2) != 0) && !ctrl) w->mouse->state &= ~BROWSER_MOUSE_MOD_2; if (((w->mouse->state & BROWSER_MOUSE_MOD_3) != 0) && !alt) w->mouse->state &= ~BROWSER_MOUSE_MOD_3; if ((w->mouse->state & BROWSER_MOUSE_CLICK_2) != 0) browser_window_mouse_click(w->bw, w->mouse->state, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); else browser_window_mouse_drag_end(w->bw, 0, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); w->mouse->state = 0; return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_LBUTTONDBLCLK: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); if ((w != NULL) && (w->bw != NULL) && (y > w->voffset)) browser_window_mouse_click(w->bw, BROWSER_MOUSE_DOUBLE_CLICK, (x + w->scrollx) / w->bw->scale, (y - w->voffset + w->scrolly) / w->bw->scale); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_NCLBUTTONDOWN: { int x,y; x = GET_X_LPARAM(lparam); y = GET_Y_LPARAM(lparam); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_ENTERMENULOOP: nsws_update_edit(w); return DefWindowProc(hwnd, msg, wparam, lparam); case WM_CONTEXTMENU: if (!nsws_ctx_menu(w, hwnd, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam))) return DefWindowProc(hwnd, msg, wparam, lparam); break; case WM_COMMAND: { switch(LOWORD(wparam)) { case NSWS_ID_FILE_QUIT: w = window_list; while (w != NULL) { PostMessage(w->main, WM_CLOSE, 0, 0); w = w->next; } netsurf_quit = true; break; case NSWS_ID_FILE_OPEN_LOCATION: SetFocus(w->urlbar); break; case NSWS_ID_FILE_OPEN_WINDOW: break; case NSWS_ID_FILE_CLOSE_WINDOW: PostMessage(hwnd, WM_CLOSE, 0, 0); break; case NSWS_ID_FILE_SAVE_PAGE: break; case NSWS_ID_FILE_SAVEAS_TEXT: break; case NSWS_ID_FILE_SAVEAS_PDF: break; case NSWS_ID_FILE_SAVEAS_DRAWFILE: break; case NSWS_ID_FILE_SAVEAS_POSTSCRIPT: break; case NSWS_ID_FILE_PRINT_PREVIEW: break; case NSWS_ID_FILE_PRINT: break; case NSWS_ID_EDIT_CUT: OpenClipboard(hwnd); EmptyClipboard(); CloseClipboard(); if (GetFocus() == w->urlbar) SendMessage(w->urlbar, WM_CUT, 0, 0); else if (w->bw != NULL) browser_window_key_press(w->bw, KEY_CUT_SELECTION); break; case NSWS_ID_EDIT_COPY: OpenClipboard(hwnd); EmptyClipboard(); CloseClipboard(); if (GetFocus() == w->urlbar) SendMessage(w->urlbar, WM_COPY, 0, 0); else if (w->bw != NULL) gui_copy_to_clipboard(w->bw->sel); break; case NSWS_ID_EDIT_PASTE: { OpenClipboard(hwnd); HANDLE h = GetClipboardData(CF_TEXT); if (h != NULL) { char *content = GlobalLock(h); LOG(("pasting %s\n", content)); GlobalUnlock(h); } CloseClipboard(); if (GetFocus() == w->urlbar) SendMessage(w->urlbar, WM_PASTE, 0, 0); else gui_paste_from_clipboard(w, 0, 0); break; } case NSWS_ID_EDIT_DELETE: if (GetFocus() == w->urlbar) SendMessage(w->urlbar, WM_CUT, 0, 0); else browser_window_key_press(w->bw, KEY_DELETE_RIGHT); break; case NSWS_ID_EDIT_SELECT_ALL: if (GetFocus() == w->urlbar) SendMessage(w->urlbar, EM_SETSEL, 0, -1); else selection_select_all(w->bw->sel); break; case NSWS_ID_EDIT_SEARCH: break; case NSWS_ID_EDIT_PREFERENCES: nsws_prefs_dialog_init(w->main); break; case NSWS_ID_NAV_BACK: if ((w->bw != NULL) && (history_back_available( w->bw->history))) { history_back(w->bw, w->bw->history); } nsws_window_update_forward_back(w); break; case NSWS_ID_NAV_FORWARD: if ((w->bw != NULL) && (history_forward_available( w->bw->history))) { history_forward(w->bw, w->bw->history); } nsws_window_update_forward_back(w); break; case NSWS_ID_NAV_HOME: browser_window_go(w->bw, default_page, 0, true); break; case NSWS_ID_NAV_STOP: browser_window_stop(w->bw); break; case NSWS_ID_NAV_RELOAD: browser_window_reload(w->bw, true); break; case NSWS_ID_NAV_LOCALHISTORY: nsws_localhistory_init(w); break; case NSWS_ID_NAV_GLOBALHISTORY: break; case NSWS_ID_VIEW_ZOOMPLUS: { int x, y; gui_window_get_scroll(w, &x, &y); if (w->bw != NULL) { browser_window_set_scale(w->bw, w->bw->scale * 1.1, true); browser_window_reformat(w->bw, w->width, w->height); } gui_window_redraw_window(w); gui_window_set_scroll(w, x, y); break; } case NSWS_ID_VIEW_ZOOMMINUS: { int x, y; gui_window_get_scroll(w, &x, &y); if (w->bw != NULL) { browser_window_set_scale(w->bw, w->bw->scale * 0.9, true); browser_window_reformat(w->bw, w->width, w->height); } gui_window_redraw_window(w); gui_window_set_scroll(w, x, y); break; } case NSWS_ID_VIEW_ZOOMNORMAL: { int x, y; gui_window_get_scroll(w, &x, &y); if (w->bw != NULL) { browser_window_set_scale(w->bw, 1.0, true); browser_window_reformat(w->bw, w->width, w->height); } gui_window_redraw_window(w); gui_window_set_scroll(w, x, y); break; } case NSWS_ID_VIEW_SOURCE: break; case NSWS_ID_VIEW_SAVE_WIN_METRICS: { RECT r; GetWindowRect(hwnd, &r); option_window_x = r.left; option_window_y = r.top; option_window_width = r.right - r.left; option_window_height = r.bottom - r.top; options_write(options_file_location); break; } case NSWS_ID_VIEW_FULLSCREEN: { RECT rdesk; if (w->fullscreen == NULL) { HWND desktop = GetDesktopWindow(); w->fullscreen = malloc(sizeof(RECT)); if ((desktop == NULL) || (w->fullscreen == NULL)) { warn_user("NoMemory", 0); break; } GetWindowRect(desktop, &rdesk); GetWindowRect(hwnd, w->fullscreen); DeleteObject(desktop); SetWindowLong(hwnd, GWL_STYLE, 0); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, rdesk.right - rdesk.left, rdesk.bottom - rdesk.top, SWP_SHOWWINDOW); } else { SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_DBLCLKS); SetWindowPos(hwnd, HWND_TOPMOST, w->fullscreen->left, w->fullscreen->top, w->fullscreen->right - w->fullscreen->left, w->fullscreen->bottom - w->fullscreen->top, SWP_SHOWWINDOW | SWP_FRAMECHANGED); free(w->fullscreen); w->fullscreen = NULL; } break; } case NSWS_ID_VIEW_DOWNLOADS: break; case NSWS_ID_VIEW_TOGGLE_DEBUG_RENDERING: html_redraw_debug = !html_redraw_debug; if (w->bw != NULL) { browser_window_reformat( w->bw, w->width, w->height); redraw(); } break; case NSWS_ID_VIEW_DEBUGGING_SAVE_BOXTREE: break; case NSWS_ID_VIEW_DEBUGGING_SAVE_DOMTREE: break; case NSWS_ID_HELP_CONTENTS: break; case NSWS_ID_HELP_GUIDE: break; case NSWS_ID_HELP_INFO: break; case NSWS_ID_HELP_ABOUT: nsws_about_dialog_init(hinstance, hwnd); break; case NSWS_ID_LAUNCH_URL: { if (GetFocus() != w->urlbar) break; int len = SendMessage(w->urlbar, WM_GETTEXTLENGTH, 0, 0); char addr[len + 1]; SendMessage(w->urlbar, WM_GETTEXT, (WPARAM) (len + 1), (LPARAM) addr); LOG(("launching %s\n", addr)); browser_window_go(w->bw, addr, 0, true); break; } case NSWS_ID_URLBAR: /* main message should already have been handled */ break; default: break; } break; } case WM_HSCROLL: { if (w->requestscrollx != 0) break; 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 -= w->width; break; case SB_PAGERIGHT: si.nPos += w->width; break; case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; default: break; } si.fMask = SIF_POS; if ((w->bw != NULL) && (w->bw->current_content != NULL)) si.nPos = MIN(si.nPos, w->bw->current_content->width * w->bw->scale - w->width); si.nPos = MAX(si.nPos, 0); SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); GetScrollInfo(hwnd, SB_HORZ, &si); if (si.nPos != mem) gui_window_set_scroll(w, w->scrollx + w->requestscrollx + si.nPos - mem, w->scrolly); break; } case WM_VSCROLL: { if (w->requestscrolly != 0) break; 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 -= w->height; break; case SB_PAGEDOWN: si.nPos += w->height; break; case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; default: break; } si.fMask = SIF_POS; if ((w->bw != NULL) && (w->bw->current_content != NULL)) si.nPos = MIN(si.nPos, w->bw->current_content->height * w->bw->scale - w->height); si.nPos = MAX(si.nPos, 0); SetScrollInfo(hwnd, SB_VERT, &si, TRUE); GetScrollInfo(hwnd, SB_VERT, &si); if (si.nPos != mem) gui_window_set_scroll(w, w->scrollx, w->scrolly + w->requestscrolly + si.nPos - mem); break; } case WM_MOUSEWHEEL: #ifdef MSH_MOUSEWHEEL case MSH_MOUSEWHEEL: /* w95 additional module MSWheel */ #endif { int i, z = GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA, 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); break; } case WM_CREATE: { HDC hdc = GetDC(hwnd); int dpi = GetDeviceCaps(hdc,LOGPIXELSY); if (dpi > 10) nscss_screen_dpi = INTTOFIX(dpi); ReleaseDC(hwnd, hdc); nsws_window_set_accels(w); nsws_window_set_ico(w); nsws_window_toolbar_create(w); nsws_window_statusbar_create(w); nsws_window_drawingarea_create(w); nsws_window_vscroll_create(w); nsws_window_hscroll_create(w); break; } case WM_PAINT: { if ((w->toolbar == NULL) || (w->urlbar == NULL) || (w->statusbar == NULL) || (w->vscroll == NULL) || (w->hscroll == NULL)) break; HWND focuswnd = GetFocus(); SetFocus(w->urlbar); SetFocus(focuswnd); current_hwnd = hwnd; current_gui = w; PAINTSTRUCT ps; BeginPaint(hwnd, &ps); /* printf("repaint dc %p erase %d from %ld,%ld to %ld,%ld\n", ps.hdc, (int)ps.fErase, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); */ PostMessage(w->toolbar, WM_PAINT, 0, 0); PostMessage(w->urlbar, WM_PAINT, 0, 0); PostMessage(w->statusbar, WM_PAINT, 0, 0); PostMessage(w->main, WM_NCPAINT, 0, 0); /* PostMessage(w->vscroll, WM_PAINT, 0, 0); PostMessage(w->hscroll, WM_PAINT, 0, 0); */ RECT r, rstatus, rtool; GetClientRect(hwnd, &r); GetWindowRect(w->toolbar, &rtool); GetWindowRect(w->statusbar, &rstatus); w->voffset = rtool.bottom - rtool.top - 1; /* 1 seems necessary */ w->height = r.bottom - w->voffset - (rstatus.bottom - rstatus.top) + 1; w->width = r.right + 1; w->redraw.left = MAX(ps.rcPaint.left, 0); w->redraw.top = MAX(ps.rcPaint.top - w->voffset, 0); w->redraw.right = MIN(ps.rcPaint.right, w->width); w->redraw.bottom = MIN(ps.rcPaint.bottom, w->height); redraw(); EndPaint(hwnd, &ps); plot.clip(0, 0, w->width, w->height); DWORD ret = DefWindowProc(hwnd, msg, wparam, lparam); if (historyactive) current_gui = NULL; return ret; break; } case WM_NCPAINT: PostMessage(w->toolbar, WM_PAINT, 0, 0); PostMessage(w->urlbar, WM_PAINT, 0, 0); return DefWindowProc(hwnd, msg, wparam, lparam); break; case WM_MOVE: DefWindowProc(hwnd, msg, wparam, lparam); gui_window_redraw_window(w); break; case WM_SIZE: { if ((w->toolbar == NULL) || (w->urlbar == NULL) || (w->statusbar == NULL)) break; int x, y; RECT rmain, rstatus, rtool; GetClientRect(hwnd, &rmain); GetClientRect(w->toolbar, &rtool); GetWindowRect(w->statusbar, &rstatus); gui_window_get_scroll(w, &x, &y); w->voffset = rtool.bottom - rtool.top; w->height = HIWORD(lparam) - w->voffset - (rstatus.bottom - rstatus.top); w->width = LOWORD(lparam); HDC hdc = GetDC(hwnd); if (w->bufferdc == NULL) w->bufferdc = CreateCompatibleDC(hdc); if (w->bufferbm != NULL) { DeleteObject(w->bufferbm); w->bufferbm = CreateCompatibleBitmap(hdc, w->width, w->height + w->voffset); SelectObject(w->bufferdc, w->bufferbm); } ReleaseDC(hwnd, hdc); w->urlbarwidth = w->width - w->ntoolbuttons * w->toolbuttondimension - 8 - NSWS_THROBBER_WIDTH; if (w->bw != NULL) { browser_window_reformat( w->bw, w->width, w->height); redraw(); } gui_window_set_scroll(w, x, y); /* re-create toolbar to adjust width of url bar holder */ DestroyWindow(w->toolbar); DestroyWindow(w->throbber); /* memorize url */ int len = SendMessage(w->urlbar, WM_GETTEXTLENGTH, 0, 0); char temp[len + 1]; SendMessage(w->urlbar, WM_GETTEXT, (WPARAM) (len + 1), (LPARAM) temp); DestroyWindow(w->urlbar); nsws_window_toolbar_create(w); SendMessage(w->urlbar, WM_SETTEXT, 0, (LPARAM) temp); /* SendMessage(w->toolbar, TB_AUTOSIZE, 0, 0); */ SendMessage(w->statusbar, WM_SIZE, 0, MAKELONG(w->width, 0)); nsws_window_update_forward_back(w); if (w->toolbar != NULL) SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_STOP, MAKELONG(TBSTATE_INDETERMINATE, 0)); return DefWindowProc(hwnd, msg, wparam, lparam); break; } case WM_CLOSE: if (--open_windows == 0) { netsurf_quit = true; } DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wparam, lparam); } return 0; } /** * creation of a new window */ static void nsws_window_create(struct gui_window *gw) { if (gw == NULL) return; LOG(("nsws_window_create %p", gw)); const char windowclassname[] = "nsws_window"; WNDCLASSEX w; HWND hwnd; INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(icc); icc.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES; #if WINVER > 0x0501 icc.dwICC |= ICC_STANDARD_CLASSES; #endif InitCommonControlsEx(&icc); 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(NULL, IDI_APPLICATION); /* -> NetSurf */ w.hCursor = LoadCursor(NULL, IDC_ARROW); w.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); w.lpszMenuName = NULL; w.lpszClassName = windowclassname; w.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* -> NetSurf */ RegisterClassEx(&w); gw->mainmenu = LoadMenu(hinstance, MAKEINTRESOURCE(NSWS_ID_MAINMENU)); gw->rclick = LoadMenu(hinstance, MAKEINTRESOURCE(NSWS_ID_CTXMENU)); LOG(("creating window for hInstance %p", hinstance)); hwnd = CreateWindow(windowclassname, "NetSurf Browser", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_DBLCLKS, CW_USEDEFAULT, CW_USEDEFAULT, gw->width, gw->height, NULL, gw->mainmenu, hinstance, NULL); if ((option_window_width >= 100) && (option_window_height >= 100) && (option_window_x >= 0) && (option_window_y >= 0)) SetWindowPos(hwnd, HWND_TOPMOST, option_window_x, option_window_y, option_window_width, option_window_height, SWP_SHOWWINDOW); ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); gw->main = hwnd; } /** * create a new gui_window to contain a browser_window * \param bw the browser_window to connect to the new gui_window */ struct gui_window * gui_create_browser_window(struct browser_window *bw, struct browser_window *clone, bool new_tab) { struct gui_window *w; w = calloc(1, sizeof(struct gui_window)); if (w == NULL) return NULL; /* connect gui window to browser window */ w->bw = bw; w->width = 600; w->height = 600; w->ntoolbuttons = NTOOLBUTTONS; w->toolbuttondimension = 32; /* includes padding of 4 every side */ w->urlbarwidth = w->width - w->toolbuttondimension * w->ntoolbuttons - 8 - NSWS_THROBBER_WIDTH; w->requestscrollx = 0; w->requestscrolly = 0; w->localhistory = NULL; w->mouse = malloc(sizeof(struct browser_mouse)); if (w->mouse == NULL) { free(w); return NULL; } w->mouse->gui = w; w->mouse->state = 0; w->mouse->pressed_x = 0; w->mouse->pressed_y = 0; if (bw != NULL) switch(bw->browser_window_type) { case BROWSER_WINDOW_NORMAL: break; case BROWSER_WINDOW_FRAME: LOG(("create frame")); break; default: LOG(("unhandled type")); } if (window_list != NULL) window_list->prev = w; w->next = window_list; window_list = w; input_window = w; open_windows++; nsws_window_create(w); return w; } HICON nsws_window_get_ico(bool large) { return large ? hIcon : hIconS; } /** * cache pointers for quick swapping */ static void nsws_window_init_pointers(void) { 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); } HWND gui_window_main_window(struct gui_window *w) { if (w == NULL) return NULL; return w->main; } HWND gui_window_toolbar(struct gui_window *w) { if (w == NULL) return NULL; return w->toolbar; } HWND gui_window_urlbar(struct gui_window *w) { if (w == NULL) return NULL; return w->urlbar; } HWND gui_window_statusbar(struct gui_window *w) { if (w == NULL) return NULL; return w->statusbar; } HWND gui_window_drawingarea(struct gui_window *w) { if (w == NULL) return NULL; return w->drawingarea; } struct nsws_localhistory *gui_window_localhistory(struct gui_window *w) { if (w == NULL) return NULL; return w->localhistory; } void gui_window_set_localhistory(struct gui_window *w, struct nsws_localhistory *l) { if (w != NULL) w->localhistory = l; } RECT *gui_window_redraw_rect(struct gui_window *w) { if (w == NULL) return NULL; return &(w->redraw); } RECT *gui_window_clip_rect(struct gui_window *w) { if (w == NULL) return NULL; return &(w->clip); } int gui_window_voffset(struct gui_window *w) { if (w == NULL) return 0; return w->voffset; } int gui_window_width(struct gui_window *w) { if (w == NULL) return 0; return w->width; } int gui_window_height(struct gui_window *w) { if (w == NULL) return 0; return w->height; } int gui_window_scrollingx(struct gui_window *w) { if (w == NULL) return 0; return w->requestscrollx; } int gui_window_scrollingy(struct gui_window *w) { if (w == NULL) return 0; return w->requestscrolly; } struct gui_window *gui_window_iterate(struct gui_window *w) { if (w == NULL) return NULL; return w->next; } struct browser_window *gui_window_browser_window(struct gui_window *w) { if (w == NULL) return NULL; return w->bw; } /** * window cleanup code */ void gui_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; } /** * set window title * \param title the [url] */ void gui_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) { warn_user("NoMemory", 0); return; } strcpy(fulltitle, title); strcat(fulltitle, " - NetSurf"); SendMessage(w->main, WM_SETTEXT, 0, (LPARAM)fulltitle); free(fulltitle); } /** * redraw a rectangle of the window */ void gui_window_redraw(struct gui_window *w, int x0, int y0, int x1, int y1) { LOG(("redraw %p %d,%d %d,%d", w, x0, y0, x1, y1)); if (w == NULL) return; w->redraw.left = x0; w->redraw.top = y0; w->redraw.right = x1; w->redraw.bottom = y1; redraw(); } /** * redraw the whole window */ void gui_window_redraw_window(struct gui_window *w) { LOG(("redraw window %p w=%d,h=%d", w, w->width, w->height)); if (w == NULL) return; w->redraw.left = 0; w->redraw.top = 0; w->redraw.right = w->width; w->redraw.bottom = w->height; redraw(); } void gui_window_update_box(struct gui_window *w, const union content_msg_data *data) { if (w == NULL) return; w->redraw.left = (long)data->redraw.x; w->redraw.top = (long)data->redraw.y; w->redraw.right =(long)(data->redraw.x + data->redraw.width); w->redraw.bottom = (long)(data->redraw.y + data->redraw.height); redraw(); } bool gui_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; } /** * scroll the window * \param sx the new 'absolute' scroll location * \param sy the new 'absolute' scroll location */ void gui_window_set_scroll(struct gui_window *w, int sx, int sy) { SCROLLINFO si; POINT p; if ((w == NULL) || (w->bw == NULL) || (w->bw->current_content == NULL)) return; /* limit scale range */ if (abs(w->bw->scale - 0.0) < 0.00001) w->bw->scale = 1.0; w->requestscrollx = sx - w->scrollx; w->requestscrolly = sy - w->scrolly; /* set the vertical scroll offset */ si.cbSize = sizeof(si); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = w->bw->current_content->height * w->bw->scale; si.nPage = w->height; si.nPos = MAX(w->scrolly + w->requestscrolly, 0); si.nPos = MIN(si.nPos, w->bw->current_content->height * w->bw->scale - w->height); SetScrollInfo(w->main, SB_VERT, &si, TRUE); /* set the horizontal scroll offset */ si.cbSize = sizeof(si); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = w->bw->current_content->width * w->bw->scale; si.nPage = w->width; si.nPos = MAX(w->scrollx + w->requestscrollx, 0); si.nPos = MIN(si.nPos, w->bw->current_content->width * w->bw->scale - w->width); SetScrollInfo(w->main, SB_HORZ, &si, TRUE); /* Set caret position */ GetCaretPos(&p); HideCaret(w->main); SetCaretPos(p.x - w->requestscrollx, p.y - w->requestscrolly); ShowCaret(w->main); RECT r, redraw; r.top = w->voffset - 1; r.bottom = w->voffset + w->height + 1; r.left = 0; r.right = w->width + 1; ScrollWindowEx(w->main, - w->requestscrollx, - w->requestscrolly, &r, NULL, NULL, &redraw, SW_INVALIDATE); gui_window_redraw(w, redraw.left + (w->requestscrollx + w->scrollx) / w->bw->scale - 1, redraw.top + (w->requestscrolly + w->scrolly) / w->bw->scale - w->voffset - 1, redraw.right + (w->requestscrollx + w->scrollx) / w->bw->scale + 1, redraw.bottom + (w->requestscrolly + w->scrolly) / w->bw->scale - w->voffset + 1); } void gui_window_scroll_visible(struct gui_window *w, int x0, int y0, int x1, int y1) { LOG(("scroll visible %s:(%p, %d, %d, %d, %d)", __func__, w, x0, y0, x1, y1)); } void gui_window_position_frame(struct gui_window *w, int x0, int y0, int x1, int y1) { LOG(("position frame %s: %d, %d, %d, %d", w->bw->name, x0, y0, x1, y1)); } void gui_window_get_dimensions(struct gui_window *w, int *width, int *height, bool scaled) { LOG(("get dimensions %p w=%d h=%d", w, w->width, w->height)); if (w == NULL) return; *width = w->width; *height = w->height; } void gui_window_update_extent(struct gui_window *w) { } /** * set the status bar message */ void gui_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 */ void gui_window_set_pointer(struct gui_window *w, gui_pointer_shape shape) { if (w == NULL) return; switch (shape) { case GUI_POINTER_POINT: /* link */ case GUI_POINTER_MENU: SetCursor(nsws_pointer.hand); break; case GUI_POINTER_CARET: /* input */ SetCursor(nsws_pointer.ibeam); break; case GUI_POINTER_CROSS: SetCursor(nsws_pointer.cross); break; case GUI_POINTER_MOVE: SetCursor(nsws_pointer.sizeall); break; case GUI_POINTER_RIGHT: case GUI_POINTER_LEFT: SetCursor(nsws_pointer.sizewe); break; case GUI_POINTER_UP: case GUI_POINTER_DOWN: SetCursor(nsws_pointer.sizens); break; case GUI_POINTER_RU: case GUI_POINTER_LD: SetCursor(nsws_pointer.sizenesw); break; case GUI_POINTER_RD: case GUI_POINTER_LU: SetCursor(nsws_pointer.sizenwse); break; case GUI_POINTER_WAIT: SetCursor(nsws_pointer.wait); break; case GUI_POINTER_PROGRESS: SetCursor(nsws_pointer.appstarting); break; case GUI_POINTER_NO_DROP: case GUI_POINTER_NOT_ALLOWED: SetCursor(nsws_pointer.no); break; case GUI_POINTER_HELP: SetCursor(nsws_pointer.help); break; default: SetCursor(nsws_pointer.arrow); break; } } struct nsws_pointers *nsws_get_pointers(void) { return &nsws_pointer; } void gui_window_hide_pointer(struct gui_window *w) { } void gui_window_set_url(struct gui_window *w, const char *url) { if (w == NULL) return; SendMessage(w->urlbar, WM_SETTEXT, 0, (LPARAM) url); } void gui_window_start_throbber(struct gui_window *w) { if (w == NULL) return; nsws_window_update_forward_back(w); if (w->mainmenu != NULL) { EnableMenuItem(w->mainmenu, NSWS_ID_NAV_STOP, MF_ENABLED); EnableMenuItem(w->mainmenu, NSWS_ID_NAV_RELOAD, MF_GRAYED); } if (w->rclick != NULL) { EnableMenuItem(w->rclick, NSWS_ID_NAV_STOP, MF_ENABLED); EnableMenuItem(w->rclick, NSWS_ID_NAV_RELOAD, MF_GRAYED); } if (w->toolbar != NULL) { SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_STOP, MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_RELOAD, MAKELONG(TBSTATE_INDETERMINATE, 0)); } w->throbbing = true; Animate_Play(w->throbber, 0, -1, -1); } void gui_window_stop_throbber(struct gui_window *w) { if (w == NULL) return; nsws_window_update_forward_back(w); if (w->mainmenu != NULL) { EnableMenuItem(w->mainmenu, NSWS_ID_NAV_STOP, MF_GRAYED); EnableMenuItem(w->mainmenu, NSWS_ID_NAV_RELOAD, MF_ENABLED); } if (w->rclick != NULL) { EnableMenuItem(w->rclick, NSWS_ID_NAV_STOP, MF_GRAYED); EnableMenuItem(w->rclick, NSWS_ID_NAV_RELOAD, MF_ENABLED); } if (w->toolbar != NULL) { SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_STOP, MAKELONG(TBSTATE_INDETERMINATE, 0)); SendMessage(w->toolbar, TB_SETSTATE, (WPARAM) NSWS_ID_NAV_RELOAD, MAKELONG(TBSTATE_ENABLED, 0)); } w->throbbing = false; Animate_Stop(w->throbber); Animate_Seek(w->throbber, 0); } /** * place caret in window */ void gui_window_place_caret(struct gui_window *w, int x, int y, int height) { if (w == NULL) return; CreateCaret(w->main, (HBITMAP)NULL, 1, height * w->bw->scale); SetCaretPos(x * w->bw->scale - w->scrollx, y * w->bw->scale + w->voffset - w->scrolly); ShowCaret(w->main); } /** * clear window caret */ void gui_window_remove_caret(struct gui_window *w) { if (w == NULL) return; HideCaret(w->main); } void gui_window_set_icon(struct gui_window *g, struct content *icon) { } void gui_window_set_search_ico(struct content *ico) { } bool save_complete_gui_save(const char *path, const char *filename, size_t len, const char *sourcedata, content_type type) { return false; } int save_complete_htmlSaveFileFormat(const char *path, const char *filename, xmlDocPtr cur, const char *encoding, int format) { return 0; } void gui_window_new_content(struct gui_window *w) { } bool gui_window_scroll_start(struct gui_window *w) { return true; } bool gui_window_box_scroll_start(struct gui_window *w, int x0, int y0, int x1, int y1) { return true; } bool gui_window_frame_resize_start(struct gui_window *w) { LOG(("resize frame\n")); return true; } void gui_window_save_as_link(struct gui_window *w, struct content *c) { } void gui_window_set_scale(struct gui_window *w, float scale) { if (w == NULL) return; w->scale = scale; LOG(("%.2f\n", scale)); } void gui_drag_save_object(gui_save_type type, struct content *c, struct gui_window *w) { } void gui_drag_save_selection(struct selection *s, struct gui_window *w) { } void gui_start_selection(struct gui_window *w) { } void gui_paste_from_clipboard(struct gui_window *w, int x, int y) { 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); } } bool gui_empty_clipboard(void) { return false; } bool gui_add_to_clipboard(const char *text, size_t length, bool space) { 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, text); if (h != NULL) { GlobalUnlock(h); EmptyClipboard(); } GlobalUnlock(hnew); SetClipboardData(CF_TEXT, hnew); return true; } bool gui_commit_clipboard(void) { return false; } static bool gui_selection_traverse_handler(const char *text, size_t length, struct box *box, void *handle, const char *space_text, size_t space_length) { if (space_text) { if (!gui_add_to_clipboard(space_text, space_length, false)) { return false; } } if (!gui_add_to_clipboard(text, length, box->space)) return false; return true; } bool gui_copy_to_clipboard(struct selection *s) { if ((s->defined) && (s->bw != NULL) && (s->bw->window != NULL) && (s->bw->window->main != NULL)) { OpenClipboard(s->bw->window->main); EmptyClipboard(); if (selection_traverse(s, gui_selection_traverse_handler, NULL)) { CloseClipboard(); return true; } } return false; } void gui_create_form_select_menu(struct browser_window *bw, struct form_control *control) { } void gui_launch_url(const char *url) { } void gui_cert_verify(struct browser_window *bw, struct content *c, const struct ssl_cert_info *certs, unsigned long num) { } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd) { char **argv = NULL; int argc = 0, argctemp = 0; size_t len; LPWSTR * argvw; if (SLEN(lpcli) > 0) { argvw = CommandLineToArgvW(GetCommandLineW(), &argc); } hinstance = hInstance; 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 * hypen flags. */ if (argv[argctemp][0] == '/') argv[argctemp][0] = '-'; } argctemp++; } return netsurf_main(argc, argv); } static void *myrealloc(void *ptr, size_t len, void *pw) { return realloc(ptr, len); } void gui_quit(void) { LOG(("gui_quit")); hubbub_finalise(myrealloc, NULL); } void gui_init(int argc, char** argv) { char buf[PATH_MAX], sbuf[PATH_MAX]; int len; LOG(("argc %d, argv %p", argc, argv)); nsws_find_resource(buf, "Aliases", "./windows/res/Aliases"); LOG(("Using '%s' as Aliases file", buf)); hubbub_error he = hubbub_initialise(buf, myrealloc, NULL); LOG(("hubbub init %d", he)); if (he != HUBBUB_OK) die("Unable to initialise HTML parsing library.\n"); /* load browser messages */ nsws_find_resource(buf, "messages", "./windows/res/messages"); LOG(("Using '%s' as Messages file", buf)); messages_load(buf); /* load browser options */ nsws_find_resource(buf, "preferences", "~/.netsurf/preferences"); LOG(("Using '%s' as Preferences file", buf)); options_file_location = strdup(buf); options_read(buf); /* set up stylesheet urls */ getcwd(sbuf, PATH_MAX); len = strlen(sbuf); strncat(sbuf, "windows/res/default.css", PATH_MAX - len); nsws_find_resource(buf, "default.css", sbuf); default_stylesheet_url = path_to_url(buf); LOG(("Using '%s' as Default CSS URL", default_stylesheet_url)); getcwd(sbuf, PATH_MAX); len = strlen(sbuf); strncat(sbuf, "windows/res/quirks.css", PATH_MAX - len); nsws_find_resource(buf, "quirks.css", sbuf); quirks_stylesheet_url = path_to_url(buf); LOG(("Using '%s' as quirks stylesheet url", quirks_stylesheet_url )); option_target_blank = false; } void gui_init2(int argc, char** argv) { struct browser_window *bw; const char *addr = NETSURF_HOMEPAGE; nsws_window_init_pointers(); LOG(("argc %d, argv %p", argc, argv)); if (argc > 1) addr = argv[1]; else if (option_homepage_url != NULL && option_homepage_url[0] != '\0') addr = option_homepage_url; else addr = default_page; LOG(("calling browser_window_create")); bw = browser_window_create(addr, 0, 0, true, false); } void gui_stdout(void) { /* mwindows compile flag normally invalidates stdout unless already redirected */ if (_get_osfhandle(fileno(stdout)) == -1) { AllocConsole(); freopen("CONOUT$", "w", stdout); } }