diff options
author | Sven Weidauer <sven@5sw.de> | 2017-06-22 20:05:15 +0200 |
---|---|---|
committer | Sven Weidauer <sven@5sw.de> | 2017-06-22 20:05:15 +0200 |
commit | 2e5519f22742e7f5751d8a6098e8479bfbc9919b (patch) | |
tree | 8a18836960ee282f55352c29f3ea48c78b2aa333 | |
parent | 711dcabe7ca4bd3551b7e4af10b98715f746fb3f (diff) | |
parent | 2b2bbbe76502b6cb528752a2dad89d3f1f6c6409 (diff) | |
download | netsurf-2e5519f22742e7f5751d8a6098e8479bfbc9919b.tar.gz netsurf-2e5519f22742e7f5751d8a6098e8479bfbc9919b.tar.bz2 |
Merge remote-tracking branch 'origin/master' into svenw/cocoa
95 files changed, 7096 insertions, 6050 deletions
diff --git a/Docs/JavaScript b/Docs/JavaScript deleted file mode 100644 index ced2fbe7c..000000000 --- a/Docs/JavaScript +++ /dev/null @@ -1,16 +0,0 @@ --------------------------------------------------------------------------------- - NetSurf: JavaScript 8 April 2013 --------------------------------------------------------------------------------- - - NetSurf may be built with primitive support for JavaScript. - - | Note: NetSurf's JavaScript handling is currently: - | - | * incomplete, - | * unsupported, - | * disabled by default. - - To test it, you may build NetSurf with JavaScript and ensure NetSurf's - "enable_javascript" run-time configuration option is set to "1". To do this - you may set the option in the frontend's settings GUI, create/edit a Choices - file, or pass --enable_javascript=1 to the executable. diff --git a/Docs/QUICK-START b/Docs/QUICK-START deleted file mode 100644 index 9ff3fb5e9..000000000 --- a/Docs/QUICK-START +++ /dev/null @@ -1,108 +0,0 @@ --------------------------------------------------------------------------------- - Quick Build Steps for NetSurf 24 February 2015 --------------------------------------------------------------------------------- - - This document provides steps for building NetSurf. - - - Grab a temporary env.sh --------------------------- - - $ wget http://git.netsurf-browser.org/netsurf.git/plain/Docs/env.sh - $ source env.sh - - - Install any packages you need -------------------------------- - - Installs all packages required to build NetSurf and the NetSurf project - libraries. - - $ ns-package-install - - If your package manager is not supported, you will have to install third - party packages manually. - - - Get the NetSurf project source code from Git ----------------------------------------------- - - $ ns-clone - - - Build and install our project libraries ------------------------------------------ - - Updates NetSurf project library sources to latest, builds and installs them. - - $ ns-pull-install - - - Switch to new NetSurf workspace ---------------------------------- - - $ rm env.sh - $ cd ~/dev-netsurf/workspace - $ source env.sh - - - Build and run NetSurf ------------------------ - - $ cd netsurf - - To build the native front end (the GTK front end on Linux, BSDs, etc) you - could do: - - $ make - $ ./nsgtk - - To build the framebuffer front end, you could do: - - $ make TARGET=framebuffer - $ ./nsfb - - - Cross Compiling -================= - - If you are cross compiling, you can follow the above steps, but when sourcing - env.sh, you should set TARGET_ABI to the appropriate triplet for your cross - compiler. For example, to cross compile for RISC OS: - - $ TARGET_ABI=arm-unknown-riscos source env.sh - - After that, the commands such as `ns-package-install` and `ns-pull-install` - will do what is appropriate for the platform you are building for. - - To do the final build of NetSurf, pass the appropriate TARGET to make. For - example, to cross compile for RISC OS: - - $ make TARGET=riscos - - Finally, you can package up your build to transfer to the system you are - developing for. For example, to produce a package for RISC OS: - - $ make TARGET=riscos package - - Getting a cross compiler set up ---------------------------------- - - We maintain cross compilation environments and an SDK for a number of - platforms. These may be found in our toolchains repository. - - $ git clone git://git.netsurf-browser.org/toolchains - - Pre-built versions of the toolchains for Debian systems are often available - via our automated build and test infrastructure: - - http://ci.netsurf-browser.org/builds/toolchains/ - - - Not working? -============== - - If the above steps are inapplicable, or don't work, you can build manually. - Follow the instructions in the BUILDING-* documents in the Docs/ directory - the NetSurf browser source tree. - diff --git a/Docs/USING-Monkey b/Docs/USING-Monkey deleted file mode 100644 index 33e504239..000000000 --- a/Docs/USING-Monkey +++ /dev/null @@ -1,318 +0,0 @@ --------------------------------------------------------------------------------- - Usage Instructions for Monkey NetSurf 13 March 2011 --------------------------------------------------------------------------------- - - This document provides usage instructions for the Monkey version of - NetSurf. - - Monkey NetSurf has been tested on Ubuntu. - -Overview -======== - - What it is - ---------- - - The NetSurf Monkey front end is a developer debug tool used to - test how the core interacts with the user interface. It allows - the developers to profile NetSurf and to interact with the core - directly as though the developer were a front end. - - What it is not - -------------- - - Monkey is not a tool for building web-crawling robots or indeed - anything other than a debug tool for the NetSurf developers. - - How to interact with nsmonkey - ----------------------------- - - In brief, monkey will produce tagged output on stdout and expect - commands on stdin. Windows are numbered and for the most part - tokens are space separated. In some cases (e.g. title or status) - the final element on the output line is a string which might have - spaces embedded within it. As such, output from nsmonkey should be - parsed a token at a time, so that when such a string is encountered, - the parser can stop splitting and return the rest. - - Commands to Monkey are namespaced. For example commands related to - browser windows are prefixed by WINDOW. - - Top level tags for nsmonkey - --------------------------- - - QUIT - - WINDOW - - Top level response tags for nsmonkey - ------------------------------------ - - GENERIC - - WARN, ERROR, DIE - - WINDOW - - DOWNLOAD_WINDOW - - SSLCERT - - 401LOGIN - - PLOT - - In the below, %something% indicates a substitution made by Monkey. - - %url% will be a URL - %id% will be an opaque ID - %n% will be a number - %bool% will be TRUE or FALSE - %str% is a string and will only ever be at the end of an output line. - - Warnings, errors etc - -------------------- - - Warnings (tagged WARN) come from the NetSurf core. - Errors (tagged ERROR) tend to come from Monkey's parsers - Death (tagged DIE) comes from the core and kills Monkey dead. - -Commands -======== - - Generic commands - ---------------- - - QUIT - Cause monkey to quit cleanly. - This will cleanly destroy open windows etc. - - Window commands - --------------- - - WINDOW NEW [%url%] - Create a new browser window, optionally giving the core - a URL to immediately navigate to. - Minimally you will receive a WINDOW NEW WIN %id% response. - - WINDOW DESTROY %id% - Destroy the given browser window. - Minimally you will recieve a WINDOW DESTROY WIN %id% response. - - WINDOW GO %id% %url% [%url%] - Cause the given browser window to visit the given URL. - Optionally you can give a referrer URL to also use (simulating - a click in the browser on a link). - Minimally you can expect throbber, url etc responses. - - WINDOW REDRAW %id% [%num% %num% %num% %num%] - Cause a browser window to redraw. Optionally you can give a - set of coordinates to simulate a partial expose of the window. - Said coordinates are in traditional X0 Y0 X1 Y1 order. - The coordinates are in canvas, not window, coordinates. So you - should take into account the scroll offsets when issuing this - command. - Minimally you can expect redraw start/stop messages and you - can likely expect some number of PLOT results. - - WINDOW RELOAD %id% - Cause a browser window to reload its current content. - Expect responses similar to a GO command. - - -Responses -========= - - Generic messages - ---------------- - - GENERIC STARTED - Monkey has started and is ready for commands - - GENERIC CLOSING_DOWN - Monkey has been told to shut down and is doing so - - GENERIC FINISHED - Monkey has finished and will now exit - - GENERIC LAUNCH URL %url% - The core asked monkey to launch the given URL - - GENERIC THUMBNAIL URL %url% - The core asked monkey to thumbnail a content without - a window. - - GENERIC POLL BLOCKING - Monkey reached a point where it could sleep waiting for - commands or scheduled timeouts. No fetches nor redraws - were pending. - - Window messages - --------------- - - WINDOW NEW WIN %id% FOR %id% CLONE %id% NEWTAB %bool% - The core asked Monkey to open a new window. The IDs for 'FOR' and - 'CLONE' are core window IDs, the WIN id is a Monkey window ID. - - WINDOW SIZE WIN %id% WIDTH %n% HEIGHT %n% - The window specified has been set to the shown width and height. - - WINDOW DESTROY WIN %id% - The core has instructed Monkey to destroy the named window. - - WINDOW TITLE WIN %id% STR %str% - The core supplied a titlebar title for the given window. - - WINDOW REDRAW WIN %id% - The core asked that Monkey redraw the given window. - - WINDOW GET_DIMENSIONS WIN %id% WIDTH %n% HEIGHT %n% - The core asked Monkey what the dimensions of the window are. - Monkey has to respond immediately and returned the supplied width - and height values to the core. - - WINDOW NEW_CONTENT WIN %id% - The core has informed Monkey that the named window has a new - content object. - - WINDOW NEW_ICON WIN %id% - The core has informed Monkey that the named window hsa a new - icon (favicon) available. - - WINDOW START_THROBBER WIN %id% - The core asked Monkey to start the throbber for the named - window. This indicates to the user that the window is busy. - - WINDOW STOP_THROBBER WIN %id% - The core asked Monkey to stop the throbber for the named - window. This indicates to the user that the window is finished. - - WINDOW SET_SCROLL WIN %id% X %n% Y %n% - The core asked Monkey to set the named window's scroll offsets - to the given X and Y position. - - WINDOW UPDATE_BOX WIN %id% X %n% Y %n% WIDTH %n% HEIGHT %n% - The core asked Monkey to redraw the given portion of the content - display. Note these coordinates refer to the content, not the - viewport which Monkey is simulating. - - WINDOW UPDATE_EXTENT WIN %id% WIDTH %n% HEIGHT %n% - The core has told us that the content in the given window has a - total width and height as shown. This allows us (along with the - window's width and height) to know the scroll limits. - - WINDOW SET_STATUS WIN %id% STR %str% - The core has told us that the given window needs its status bar - updating with the given message. - - WINDOW SET_POINTER WIN %id% POINTER %id% - The core has told us to update the mouse pointer for the given - window to the given pointer ID. - - WINDOW SET_SCALE WIN %id% SCALE %n% - The core has asked us to scale the given window by the given scale - factor. - - WINDOW SET_URL WIN %id% URL %url% - The core has informed us that the given window's URL bar needs - updating to the given url. - - WINDOW GET_SCROLL WIN %id% X %n% Y %n% - The core asked Monkey for the scroll offsets. Monkey returned the - numbers shown for the window named. - - WINDOW SCROLL_START WIN %id% - The core asked Monkey to scroll the named window to the top/left. - - WINDOW POSITION_FRAME WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to position the named window as a frame at - the given coordinates of its parent. - - WINDOW SCROLL_VISIBLE WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to scroll the named window until the - indicated box is visible. - - WINDOW PLACE_CARET WIN %id% X %n% Y %n% HEIGHT %n% - The core asked Monkey to render a caret in the named window at the - indicated position with the indicated height. - - WINDOW REMOVE_CARET WIN %id% - The core asked Monkey to remove any caret in the named window. - - WINDOW SCROLL_START WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to scroll the named window to the start of - the given box. - - WINDOW SELECT_MENU WIN %id% - The core asked Monkey to produce a selection menu for the named - window. - - WINDOW SAVE_LINK WIN %id% URL %url% TITLE %str% - The core asked Monkey to save a link from the given window with - the given URL and anchor title. - - WINDOW THUMBNAIL WIN %id% URL %url% - The core asked Monkey to render a thumbnail for the given window - which is currently at the given URL. - - WINDOW REDRAW WIN %id% START - WINDOW REDRAW WIN %id% STOP - The core wraps redraws in these messages. Thus PLOT responses can - be allocated to the appropriate window. - - Download window messages - ------------------------ - - DOWNLOAD_WINDOW CREATE DWIN %id% WIN %id% - The core asked Monkey to create a download window owned by the - given browser window. - - DOWNLOAD_WINDOW DATA DWIN %id% SIZE %n% DATA %str% - The core asked Monkey to update the named download window with - the given byte size and data string. - - DOWNLOAD_WINDOW ERROR DWIN %id% ERROR %str% - The core asked Monkey to update the named download window with - the given error message. - - DOWNLOAD_WINDOW DONE DWIN %id% - The core asked Monkey to destroy the named download window. - - SSL Certificate messages - ------------------------ - - SSLCERT VERIFY CERT %id% URL %url% - The core asked Monkey to say whether or not a given SSL - certificate is OK. - - 401 Login messages - ------------------ - - 401LOGIN OPEN M4 %id% URL %url% REALM %str% - The core asked Monkey to ask for identification for the named - realm at the given URL. - - Plotter messages - ---------------- - - Note, Monkey won't clip coordinates, but sometimes the core does. - - PLOT CLIP X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to clip plotting to the given clipping - rectangle (X0,Y0) (X1,Y1) - - PLOT TEXT X %n% Y %n% STR %str% - The core asked Monkey to plot the given string at the - given coordinates. - - PLOT LINE X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to plot a line with the given start - and end coordinates. - - PLOT RECT X0 %n% Y0 %n% X1 %n% Y1 %n% - The core asked Monkey to plot a rectangle with the given - coordinates as the corners. - - PLOT BITMAP X %n% Y %n% WIDTH %n% HEIGHT %n% - The core asked Monkey to plot a bitmap at the given - coordinates, scaled to the given width/height. diff --git a/Docs/core-window-interface b/Docs/core-window-interface deleted file mode 100644 index 83c5f586b..000000000 --- a/Docs/core-window-interface +++ /dev/null @@ -1,679 +0,0 @@ -Core Window Interface -===================== - -The NetSurf core provides an optional API to frontend implementations -which allows a number of "standard" window content interfaces to be -provided. - -The currently available user interfaces are: - - - Cookies - - Global history - - Hotlist - - SSL certificate view - -Although not currently included in future additional user interfaces -will be available for: - - - local history - - browser render - -To be clear these are generic implementations of this functionality -that any frontend may use. Frontends are free to implement these -interfaces in any manner as they see fit, the corewindow interface -simply provides a default. - -core window API ---------------- - -The API is fairly simple and simply involves passing a callback table -and context pointer to the interface element being constructed. - -The header that defines the callback interface is netsurf/core_window.h - -The callback table contains five function pointer interfaces which the -frontend must implement for the core. - - - invalidate - invalidate an area of a window - - - update_size - Update the limits of the window - - - scroll_visible - Scroll the window to make area visible - - - get_window_dimensions - Get window viewport dimensions - - - drag_status - Inform corewindow owner of drag status - -Each callback will be passed the context pointer for the corewindow -instance and the relevant additional information necessary to perform -the operation. - -Each exported user interface element wraps this generic interface with -a concrete implementation. For example the SSL certificate viewer is -initialised with: - -nserror sslcert_viewer_init(struct core_window_callback_table *cw_t, - void *core_window_handle, - struct sslcert_session_data *ssl_d); - -This call creates a context which will display and navigate the ssl -session data passed. The frontend must service the callbacks from the -core to provide the necessary interactions with the frontend windowing -system. - -These actions should ideally use the standard frontend window -processing. So for the GTK frontend when the core calls the invalidate -operation it simply marks the area passed as damaged (using -gtk_widget_queue_draw_area()) and lets the standard expose event cause -the redraw to occur. - -If the frontend needs to redraw an area of a window (perhaps an expose -event occurred or the window has had an area marked as invalid) it -must call the core window API wrappers implementation which will -perform the plot operations required to update an area of the window. - -e.g in the case of ssl certificate viewer - -void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d, - int x, int y, struct rect *clip, - const struct redraw_context *ctx); - -would perform the plot operations for that SSL data window. - -Usage ------ - -The usage pattern that is expected is for a frontend to create a core -window implementation that implements the necessary five API in a -generic way and allows the frontend to provide the specific -specialisation for each of the user interface elements it wishes to -use (cookies, SSL viewer etc). - -The GTK frontend for example: - -has source corewindow.[ch] which implement the five core callbacks -using generic GTK operations (invalidate calls -gtk_widget_queue_draw_area() etc.) and then provides additional -operations on a GTK drawing area object to attach expose event -processing, keypress processing etc. - -The GTK corewindow (not to be confused with the core window API -itself, this is purely the gtk wrapper) is used by ssl_cert.c which -creates a nsgtk_crtvrfy_window structure containing the -nsgtk_corewindow structure. It attaches actual GTK window handles to -this structure and populates elements of nsgtk_corewindow and then -calls sslcert_viewer_init() directly. - -frontend skeleton ------------------ - -An example core window implementation for a frontend ssl certificate -viewer is presented here. This implements the suggested usage above -and provides generic corewindow helpers. - - -frontends/example/corewindow.h ------------------------------- - -/* - * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef EXAMPLE_COREWINDOW_H -#define EXAMPLE_COREWINDOW_H - -#include "netsurf/core_window.h" - -/** - * example core window state - */ -struct example_corewindow { - - - /* - * Any variables common to any frontend window would go here. - * e.g. drawing area handles, toolkit pointers or other state - */ - example_toolkit_widget *tk_widget; - - - - /** drag status set by core */ - core_window_drag_status drag_staus; - - /** table of callbacks for core window operations */ - struct core_window_callback_table *cb_table; - - /** - * callback to draw on drawable area of example core window - * - * \param example_cw The example core window structure. - * \param r The rectangle of the window that needs updating. - * \return NSERROR_OK on success otherwise apropriate error code - */ - nserror (*draw)(struct example_corewindow *example_cw, struct rect *r); - - /** - * callback for keypress on example core window - * - * \param example_cw The example core window structure. - * \param nskey The netsurf key code. - * \return NSERROR_OK if key processed, - * NSERROR_NOT_IMPLEMENTED if key not processed - * otherwise apropriate error code - */ - nserror (*key)(struct example_corewindow *example_cw, uint32_t nskey); - - /** - * callback for mouse event on example core window - * - * \param example_cw The example core window structure. - * \param mouse_state mouse state - * \param x location of event - * \param y location of event - * \return NSERROR_OK on sucess otherwise apropriate error code. - */ - nserror (*mouse)(struct example_corewindow *example_cw, browser_mouse_state mouse_state, int x, int y); -}; - -/** - * initialise elements of example core window. - * - * As a pre-requisite the draw, key and mouse callbacks must be defined - * - * \param example_cw A example core window structure to initialise - * \return NSERROR_OK on successful initialisation otherwise error code. - */ -nserror example_corewindow_init(struct example_corewindow *example_cw); - -/** - * finalise elements of example core window. - * - * \param example_cw A example core window structure to initialise - * \return NSERROR_OK on successful finalisation otherwise error code. - */ -nserror example_corewindow_fini(struct example_corewindow *example_cw); - -#endif - -frontends/example/corewindow.c ------------------------------- - -/* - * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * \file - * EXAMPLE generic core window interface. - * - * Provides interface for core renderers to the example toolkit drawable area. - * - * This module is an object that must be encapsulated. Client users - * should embed a struct example_corewindow at the beginning of their - * context for this display surface, fill in relevant data and then - * call example_corewindow_init() - * - * The example core window structure requires the callback for draw, key and - * mouse operations. - */ - -#include <assert.h> -#include <string.h> -#include <math.h> - -#include "utils/log.h" -#include "utils/utils.h" -#include "utils/messages.h" -#include "utils/utf8.h" -#include "netsurf/keypress.h" -#include "netsurf/mouse.h" -#include "netsurf/plot_style.h" - -/* extremely likely there will be additional headers required in a real frontend */ -#include "example/corewindow.h" - - -/* toolkit event handlers that do generic things and call internal callbacks */ - - -static bool -example_cw_mouse_press_event(toolkit_widget *widget, toolkit_button bt, int x, int y, void *ctx) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)ctx; - - example_cw->mouse(example_cw, state, x, y); - - return true; -} - -static bool -example_cw_keyrelease_event(toolkit_widget *widget, void *ctx) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)ctx; - - example_cw->key(example_cw, keycode); - - return true; -} - - - -/* signal handler for toolkit window redraw */ -static bool -example_cw_draw_event(toolkit_widget *widget, - toolkit_area *tk_area, - void *ctx) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)ctx; - struct rect clip; - - clip.x0 = tk_area.x; - clip.y0 = tk_area.y; - clip.x1 = tk_area.width; - clip.y1 = tk_area.height; - - example_cw->draw(example_cw, &clip); - - return true; -} - - -/** - * callback from core to request a redraw - */ -static nserror -example_cw_invalidate(struct core_window *cw, const struct rect *r) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)cw; - - toolkit_widget_queue_draw_area(example_cw->widget, - r->x0, r->y0, - r->x1 - r->x0, r->y1 - r->y0); -} - - -static void -example_cw_update_size(struct core_window *cw, int width, int height) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)cw; - - toolkit_widget_set_size_request(EXAMPLE_WIDGET(example_cw->drawing_area), - width, height); -} - - -static void -example_cw_scroll_visible(struct core_window *cw, const struct rect *r) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)cw; - - toolkit_scroll_widget(example_cw->widget, r); -} - - -static void -example_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)cw; - - *width = toolkit_get_widget_width(example_cw->widget); - *height = toolkit_get_widget_height(example_cw->widget); -} - - -static void -example_cw_drag_status(struct core_window *cw, core_window_drag_status ds) -{ - struct example_corewindow *example_cw = (struct example_corewindow *)cw; - example_cw->drag_staus = ds; -} - - -struct core_window_callback_table example_cw_cb_table = { - .invalidate = example_cw_invalidate, - .update_size = example_cw_update_size, - .scroll_visible = example_cw_scroll_visible, - .get_window_dimensions = example_cw_get_window_dimensions, - .drag_status = example_cw_drag_status -}; - -/* exported function documented example/corewindow.h */ -nserror example_corewindow_init(struct example_corewindow *example_cw) -{ - /* setup the core window callback table */ - example_cw->cb_table = &example_cw_cb_table; - - /* frontend toolkit specific method of causing example_cw_draw_event to be called when a drawing operation is required */ - toolkit_connect_draw_event(example_cw->tk_widget, - example_cw_draw_event, - example_cw); - - /* frontend toolkit specific method of causing example_cw_button_press_event to be called when a button press occours */ - toolkit_connect_button_press_event(example_cw->tk_widget, - example_cw_button_press_event, - example_cw); - - /* frontend toolkit specific method of causing example_cw_button_release_event to be called when a button release occours */ - toolkit_connect_button_release_event(example_cw->tk_widget, - example_cw_button_release_event, - example_cw); - - /* frontend toolkit specific method of causing example_cw_motion_notify_event to be called when there is motion over the widget */ - toolkit_connect_motion_event(example_cw->tk_widget, - example_cw_motion_notify_event, - example_cw); - - /* frontend toolkit specific method of causing example_cw_key_press_event to be called when a key press occours */ - toolkit_connect_button_press_event(example_cw->tk_widget, - example_cw_key_press_event, - example_cw); - - /* frontend toolkit specific method of causing example_cw_key_release_event to be called when a key release occours */ - toolkit_connect_button_release_event(example_cw->tk_widget, - example_cw_key_release_event, - example_cw); - - - return NSERROR_OK; -} - -/* exported interface documented in example/corewindow.h */ -nserror example_corewindow_fini(struct example_corewindow *example_cw) -{ - return NSERROR_OK; -} - - -frontends/example/ssl_cert.h ----------------------------- - -/* - * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef NETSURF_EXAMPLE_SSL_CERT_H -#define NETSURF_EXAMPLE_SSL_CERT_H 1 - -struct nsurl; -struct ssl_cert_info; - -/** - * Prompt the user to verify a certificate with issuse. - * - * \param url The URL being verified. - * \param certs The certificate to be verified - * \param num The number of certificates to be verified. - * \param cb Callback upon user decision. - * \param cbpw Context pointer passed to cb - * \return NSERROR_OK or error code if prompt creation failed. - */ -nserror example_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw); - -#endif - -frontends/example/ssl_cert.c ----------------------------- - -/* - * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * \file - * Implementation of example certificate viewing using example core windows. - */ - -#include <stdint.h> -#include <stdlib.h> - -#include "utils/log.h" -#include "netsurf/keypress.h" -#include "netsurf/plotters.h" -#include "desktop/sslcert_viewer.h" - -#include "example/corewindow.h" - - -/** - * EXAMPLE certificate viewing window context - */ -struct example_crtvrfy_window { - /** example core window context */ - struct example_corewindow core; - - /** SSL certificate viewer context data */ - struct sslcert_session_data *ssl_data; -}; - -/** - * destroy a previously created certificate view - */ -static nserror example_crtvrfy_destroy(struct example_crtvrfy_window *crtvrfy_win) -{ - nserror res; - - res = sslcert_viewer_fini(crtvrfy_win->ssl_data); - if (res == NSERROR_OK) { - res = example_corewindow_fini(&crtvrfy_win->core); - toolkit_windown_destroy(crtvrfy_win->window); - free(crtvrfy_win); - } - return res; -} - -static void -example_crtvrfy_accept(ExampleButton *w, gpointer data) -{ - struct example_crtvrfy_window *crtvrfy_win; - crtvrfy_win = (struct example_crtvrfy_window *)data; - - sslcert_viewer_accept(crtvrfy_win->ssl_data); - - example_crtvrfy_destroy(crtvrfy_win); -} - -static void -example_crtvrfy_reject(ExampleWidget *w, gpointer data) -{ - struct example_crtvrfy_window *crtvrfy_win; - crtvrfy_win = (struct example_crtvrfy_window *)data; - - sslcert_viewer_reject(crtvrfy_win->ssl_data); - - example_crtvrfy_destroy(crtvrfy_win); -} - - -/** - * callback for mouse action for certificate verify on core window - * - * \param example_cw The example core window structure. - * \param mouse_state netsurf mouse state on event - * \param x location of event - * \param y location of event - * \return NSERROR_OK on success otherwise apropriate error code - */ -static nserror -example_crtvrfy_mouse(struct example_corewindow *example_cw, - browser_mouse_state mouse_state, - int x, int y) -{ - struct example_crtvrfy_window *crtvrfy_win; - /* technically degenerate container of */ - crtvrfy_win = (struct example_crtvrfy_window *)example_cw; - - sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y); - - return NSERROR_OK; -} - -/** - * callback for keypress for certificate verify on core window - * - * \param example_cw The example core window structure. - * \param nskey The netsurf key code - * \return NSERROR_OK on success otherwise apropriate error code - */ -static nserror -example_crtvrfy_key(struct example_corewindow *example_cw, uint32_t nskey) -{ - struct example_crtvrfy_window *crtvrfy_win; - - /* technically degenerate container of */ - crtvrfy_win = (struct example_crtvrfy_window *)example_cw; - - if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) { - return NSERROR_OK; - } - return NSERROR_NOT_IMPLEMENTED; -} - -/** - * callback on draw event for certificate verify on core window - * - * \param example_cw The example core window structure. - * \param r The rectangle of the window that needs updating. - * \return NSERROR_OK on success otherwise apropriate error code - */ -static nserror -example_crtvrfy_draw(struct example_corewindow *example_cw, struct rect *r) -{ - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = &example_plotters - }; - struct example_crtvrfy_window *crtvrfy_win; - - /* technically degenerate container of */ - crtvrfy_win = (struct example_crtvrfy_window *)example_cw; - - sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx); - - return NSERROR_OK; -} - -/* exported interface documented in example/ssl_cert.h */ -nserror example_cert_verify(struct nsurl *url, - const struct ssl_cert_info *certs, - unsigned long num, - nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - struct example_crtvrfy_window *ncwin; - nserror res; - - ncwin = malloc(sizeof(struct example_crtvrfy_window)); - if (ncwin == NULL) { - return NSERROR_NOMEM; - } - - res = toolkit_create_window(&ncwin->window); - if (res != NSERROR_OK) { - LOG("SSL UI builder init failed"); - free(ncwin); - return res; - } - - /* store the widget that the toolkit is drawing into */ - ncwin->core.widget = toolkit_get_widget(ncwin->window, "SSLDrawingArea")); - - /* would typicaly setup toolkit accept/reject buttons etc. here */ - toolkit_connect_button_press(ncwin->tk_accept_button, - example_crtvrfy_accept, - ncwin); - - - /* initialise example core window */ - ncwin->core.draw = example_crtvrfy_draw; - ncwin->core.key = example_crtvrfy_key; - ncwin->core.mouse = example_crtvrfy_mouse; - - res = example_corewindow_init(&ncwin->core); - if (res != NSERROR_OK) { - free(ncwin); - return res; - } - - /* initialise certificate viewing interface */ - res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, - &ncwin->ssl_data); - if (res != NSERROR_OK) { - free(ncwin); - return res; - } - - res = sslcert_viewer_init(ncwin->core.cb_table, - (struct core_window *)ncwin, - ncwin->ssl_data); - if (res != NSERROR_OK) { - free(ncwin); - return res; - } - - toolkit_widget_show(ncwin->window); - - return NSERROR_OK; -} @@ -890,7 +890,7 @@ install: all-program install-$(TARGET) .PHONY: docs -docs: Docs/Doxyfile +docs: docs/Doxyfile doxygen $< diff --git a/content/urldb.c b/content/urldb.c index d702e581b..313ec316d 100644 --- a/content/urldb.c +++ b/content/urldb.c @@ -696,8 +696,8 @@ static bool urldb__host_is_ip_address(const char *host) } ipv6_addr_len = host_len - 2; - if (ipv6_addr_len > sizeof(ipv6_addr)) { - ipv6_addr_len = sizeof(ipv6_addr); + if (ipv6_addr_len >= sizeof(ipv6_addr)) { + ipv6_addr_len = sizeof(ipv6_addr) - 1; } strncpy(ipv6_addr, sane_host + 1, ipv6_addr_len); ipv6_addr[ipv6_addr_len] = '\0'; @@ -849,7 +849,7 @@ urldb_iterate_partial_host(struct search_node *root, * * Given: http://www.example.org/a/b/c/d//e * and assuming a path tree: - * . + * ^ * / \ * a1 b1 * / \ diff --git a/desktop/browser.c b/desktop/browser.c index 4b6a5bbd0..e7ff158f9 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -593,7 +593,7 @@ static void browser_window_set_selection(struct browser_window *bw, * scrolls the viewport to ensure the specified rectangle of the * content is shown. * - * \param gw gui_window to scroll + * \param bw window to scroll * \param rect The rectangle to ensure is shown. * \return NSERROR_OK on success or apropriate error code. */ diff --git a/desktop/browser_history.c b/desktop/browser_history.c index cf70c4700..dbbc67daf 100644 --- a/desktop/browser_history.c +++ b/desktop/browser_history.c @@ -31,13 +31,11 @@ #include "utils/log.h" #include "utils/utils.h" #include "netsurf/layout.h" -#include "netsurf/plotters.h" #include "netsurf/content.h" #include "content/hlcache.h" #include "content/urldb.h" #include "netsurf/bitmap.h" -#include "desktop/system_colour.h" #include "desktop/gui_internal.h" #include "desktop/browser_history.h" #include "desktop/browser_private.h" @@ -47,39 +45,6 @@ #define RIGHT_MARGIN 50 #define BOTTOM_MARGIN 30 -struct history_page { - nsurl *url; /**< Page URL, never 0. */ - lwc_string *frag_id; /** Fragment identifier, or 0. */ - char *title; /**< Page title, never 0. */ -}; - -/** A node in the history tree. */ -struct history_entry { - struct history_page page; - struct history_entry *back; /**< Parent. */ - struct history_entry *next; /**< Next sibling. */ - struct history_entry *forward; /**< First child. */ - struct history_entry *forward_pref; /**< Child in direction of - current entry. */ - struct history_entry *forward_last; /**< Last child. */ - unsigned int children; /**< Number of children. */ - int x; /**< Position of node. */ - int y; /**< Position of node. */ - struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */ -}; - -/** History tree for a window. */ -struct history { - /** First page in tree (page that window opened with). */ - struct history_entry *start; - /** Current position in tree. */ - struct history_entry *current; - /** Width of layout. */ - int width; - /** Height of layout. */ - int height; -}; - /** * Clone a history entry @@ -236,208 +201,9 @@ static void browser_window_history__layout(struct history *history) history->height += BOTTOM_MARGIN / 2; } -/** plot style for drawing lines between nodes */ -static plot_style_t pstyle_line = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_width = 2, -}; - -/** plot style for drawing background */ -static plot_style_t pstyle_bg = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; - -/** plot style for drawing rectangle round unselected nodes */ -static plot_style_t pstyle_rect = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_width = 1, -}; - -/** plot style for drawing rectangle round selected nodes */ -static plot_style_t pstyle_rect_sel = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_width = 3, -}; - -/** plot style for font on unselected nodes */ -static plot_font_style_t pfstyle_node = { - .family = PLOT_FONT_FAMILY_SANS_SERIF, - .size = 8 * FONT_SIZE_SCALE, - .weight = 400, - .flags = FONTF_NONE, -}; - -/** plot style for font on unselected nodes */ -static plot_font_style_t pfstyle_node_sel = { - .family = PLOT_FONT_FAMILY_SANS_SERIF, - .size = 8 * FONT_SIZE_SCALE, - .weight = 900, - .flags = FONTF_NONE, -}; - -/** - * Recursively redraw a history_entry. - * - * \param history history containing the entry - * \param entry entry to render - * \param x0 area top left x coordinate - * \param y0 area top left y coordinate - * \param x1 area bottom right x coordinate - * \param y1 area bottom right y coordinate - * \param x window x offset - * \param y window y offset - * \param clip clip redraw - * \param ctx current redraw context - */ -static bool -browser_window_history__redraw_entry(struct history *history, - struct history_entry *entry, - int x0, int y0, int x1, int y1, - int x, int y, bool clip, - const struct redraw_context *ctx) -{ - size_t char_offset; - int actual_x; - struct history_entry *child; - int tailsize = 5; - int xoffset = x - x0; - int yoffset = y - y0; - - plot_style_t *pstyle; - plot_font_style_t *pfstyle; - struct rect rect; - nserror res; - - /* setup plot styles */ - if (entry == history->current) { - pstyle = &pstyle_rect_sel; - pfstyle = &pfstyle_node_sel; - } else { - pstyle = &pstyle_rect; - pfstyle = &pfstyle_node; - } - - /* setup clip area */ - if (clip) { - rect.x0 = x0 + xoffset; - rect.y0 = y0 + yoffset; - rect.x1 = x1 + xoffset; - rect.y1 = y1 + yoffset; - res = ctx->plot->clip(ctx, &rect); - if (res != NSERROR_OK) { - return false; - } - } - - /* Only attempt to plot bitmap if it is present */ - if (entry->bitmap != NULL) { - res = ctx->plot->bitmap(ctx, - entry->bitmap, - entry->x + xoffset, - entry->y + yoffset, - WIDTH, HEIGHT, - 0xffffff, - 0); - if (res != NSERROR_OK) { - return false; - } - } - - rect.x0 = entry->x - 1 + xoffset; - rect.y0 = entry->y - 1 + yoffset; - rect.x1 = entry->x + xoffset + WIDTH; - rect.y1 = entry->y + yoffset + HEIGHT; - res = ctx->plot->rectangle(ctx, pstyle, &rect); - if (res != NSERROR_OK) { - return false; - } - - res = guit->layout->position(plot_style_font, entry->page.title, - strlen(entry->page.title), WIDTH, - &char_offset, &actual_x); - if (res != NSERROR_OK) { - return false; - } - - res = ctx->plot->text(ctx, - pfstyle, - entry->x + xoffset, - entry->y + HEIGHT + 12 + yoffset, - entry->page.title, - char_offset); - if (res != NSERROR_OK) { - return false; - } - - /* for each child node draw a line and recurse redraw into it */ - for (child = entry->forward; child; child = child->next) { - rect.x0 = entry->x + WIDTH + xoffset; - rect.y0 = entry->y + HEIGHT / 2 + yoffset; - rect.x1 = entry->x + WIDTH + tailsize + xoffset; - rect.y1 = entry->y + HEIGHT / 2 + yoffset; - res = ctx->plot->line(ctx, &pstyle_line, &rect); - if (res != NSERROR_OK) { - return false; - } - - rect.x0 = entry->x + WIDTH + tailsize + xoffset; - rect.y0 = entry->y + HEIGHT / 2 + yoffset; - rect.x1 = child->x - tailsize + xoffset; - rect.y1 = child->y + HEIGHT / 2 + yoffset; - res = ctx->plot->line(ctx, &pstyle_line, &rect); - if (res != NSERROR_OK) { - return false; - } - - rect.x0 = child->x - tailsize + xoffset; - rect.y0 = child->y + HEIGHT / 2 + yoffset; - rect.x1 = child->x + xoffset; - rect.y1 = child->y + HEIGHT / 2 + yoffset; - res = ctx->plot->line(ctx, &pstyle_line, &rect); - if (res != NSERROR_OK) { - return false; - } - - if (!browser_window_history__redraw_entry(history, child, - x0, y0, x1, y1, x, y, clip, ctx)) { - return false; - } - } - - return true; -} - - -/** - * Find the history entry at a position. - * - * \param entry entry to search from - * \param x coordinate - * \param y coordinate - * \return an entry if found, 0 if none - */ - -static struct history_entry *browser_window_history__find_position( - struct history_entry *entry, int x, int y) -{ - struct history_entry *child; - struct history_entry *found; - - if (!entry) - return 0; - if (entry->x <= x && x <= entry->x + WIDTH && - entry->y <= y && y <= entry->y + HEIGHT) - return entry; - for (child = entry->forward; child; child = child->next) { - found = browser_window_history__find_position(child, x, y); - if (found) - return found; - } - return 0; -} /** * Enumerate subentries in history @@ -478,29 +244,8 @@ static bool browser_window_history__enumerate_entry( /* exported interface documented in desktop/browser_history.h */ nserror browser_window_history_create(struct browser_window *bw) { - nserror res; struct history *history; - res = ns_system_colour_char("Window", &pstyle_bg.fill_colour); - if (res != NSERROR_OK) { - return res; - } - pfstyle_node.background = pstyle_bg.fill_colour; - pfstyle_node_sel.background = pstyle_bg.fill_colour; - - res = ns_system_colour_char("GrayText", &pstyle_line.stroke_colour); - if (res != NSERROR_OK) { - return res; - } - pstyle_rect.stroke_colour = pstyle_line.stroke_colour; - pfstyle_node.foreground = pstyle_line.stroke_colour; - - res = ns_system_colour_char("Highlight", &pstyle_rect_sel.stroke_colour); - if (res != NSERROR_OK) { - return res; - } - pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour; - bw->history = NULL; history = calloc(1, sizeof *history); @@ -769,98 +514,6 @@ nserror browser_window_history_go(struct browser_window *bw, /* exported interface documented in desktop/browser_history.h */ -void browser_window_history_size(struct browser_window *bw, - int *width, int *height) -{ - assert(bw != NULL); - assert(bw->history != NULL); - - *width = bw->history->width; - *height = bw->history->height; -} - - -/* exported interface documented in desktop/browser_history.h */ -bool browser_window_history_redraw(struct browser_window *bw, - const struct redraw_context *ctx) -{ - struct history *history; - - assert(bw != NULL); - history = bw->history; - - if (history == NULL) { - LOG("Attempt to draw NULL history."); - return false; - } - - if (!history->start) - return true; - - return browser_window_history__redraw_entry(history, history->start, - 0, 0, 0, 0, 0, 0, false, ctx); -} - - -/* exported interface documented in desktop/browser_history.h */ -bool browser_window_history_redraw_rectangle(struct browser_window *bw, - int x0, int y0, int x1, int y1, - int x, int y, const struct redraw_context *ctx) -{ - struct history *history; - - assert(bw != NULL); - history = bw->history; - - if (!history->start) - return true; - - return browser_window_history__redraw_entry(history, history->start, - x0, y0, x1, y1, x, y, true, ctx); -} - - -/* exported interface documented in desktop/browser_history.h */ -bool browser_window_history_click(struct browser_window *bw, - int x, int y, bool new_window) -{ - struct history_entry *entry; - struct history *history; - - assert(bw != NULL); - history = bw->history; - - entry = browser_window_history__find_position(history->start, x, y); - if (!entry) - return false; - if (entry == history->current) - return false; - - browser_window_history_go(bw, entry, new_window); - - return true; -} - - -/* exported interface documented in desktop/browser_history.h */ -const char *browser_window_history_position_url(struct browser_window *bw, - int x, int y) -{ - struct history_entry *entry; - struct history *history; - - assert(bw != NULL); - history = bw->history; - - entry = browser_window_history__find_position(history->start, x, y); - if (!entry) - return 0; - - return nsurl_access(entry->page.url); -} - - -/* exported interface documented in desktop/browser_history.h */ void browser_window_history_enumerate_forward(const struct browser_window *bw, browser_window_history_enumerate_cb cb, void *user_data) { @@ -907,10 +560,9 @@ void browser_window_history_enumerate(const struct browser_window *bw, /* exported interface documented in desktop/browser_history.h */ -const char *browser_window_history_entry_get_url( - const struct history_entry *entry) +nsurl *browser_window_history_entry_get_url(const struct history_entry *entry) { - return nsurl_access(entry->page.url); + return nsurl_ref(entry->page.url); } diff --git a/desktop/browser_history.h b/desktop/browser_history.h index 8ffb6125b..9140e2ce0 100644 --- a/desktop/browser_history.h +++ b/desktop/browser_history.h @@ -16,71 +16,27 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Browser history tree (interface). +/** + * \file + * Interface to browser history operations + * + * The are operations on a browsing contexts history. These interfaces + * allow navigation forward and backwards in the history as well as + * enumerating the entries. + * + * The local history viewing is distinct via corewindow defined in + * desktop/local_history.h */ -#ifndef _NETSURF_DESKTOP_BROWSER_HISTORY_H_ -#define _NETSURF_DESKTOP_BROWSER_HISTORY_H_ +#ifndef NETSURF_DESKTOP_BROWSER_HISTORY_H +#define NETSURF_DESKTOP_BROWSER_HISTORY_H #include <stdbool.h> -#include <libwapcaplet/libwapcaplet.h> #include "utils/errors.h" -struct hlcache_handle; struct browser_window; struct history_entry; -struct redraw_context; - -/** - * Create a new history tree for a browser window window. - * - * \param bw browser window to create history for. - * - * \return NSERROR_OK or appropriate error otherwise - */ -nserror browser_window_history_create(struct browser_window *bw); - -/** - * Clone a bw's history tree for new bw - * - * \param existing browser window with history to clone. - * \param clone browser window to make cloned history for. - * - * \return NSERROR_OK or appropriate error otherwise - */ -nserror browser_window_history_clone(const struct browser_window *existing, - struct browser_window *clone); -/** - * Insert a url into the history tree. - * - * \param bw browser window with history object - * \param content content to add to history - * \param frag_id fragment identifier, or NULL. - * \return NSERROR_OK or error code on faliure. - * - * The page is added after the current entry and becomes current. - */ -nserror browser_window_history_add(struct browser_window *bw, - struct hlcache_handle *content, lwc_string *frag_id); - -/** - * Update the thumbnail for the current entry. - * - * \param bw The browser window to update the history within. - * \param content content for current entry - * \return NSERROR_OK or error code on faliure. - */ -nserror browser_window_history_update(struct browser_window *bw, - struct hlcache_handle *content); - -/** - * Free a history structure. - * - * \param bw The browser window to destroy the history within. - */ -void browser_window_history_destroy(struct browser_window *bw); /** * Go back in the history. @@ -91,6 +47,7 @@ void browser_window_history_destroy(struct browser_window *bw); */ nserror browser_window_history_back(struct browser_window *bw, bool new_window); + /** * Go forward in the history. * @@ -100,6 +57,7 @@ nserror browser_window_history_back(struct browser_window *bw, bool new_window); */ nserror browser_window_history_forward(struct browser_window *bw, bool new_window); + /** * Check whether it is pssible to go back in the history. * @@ -108,6 +66,7 @@ nserror browser_window_history_forward(struct browser_window *bw, bool new_windo */ bool browser_window_history_back_available(struct browser_window *bw); + /** * Check whether it is pssible to go forwards in the history. * @@ -116,63 +75,6 @@ bool browser_window_history_back_available(struct browser_window *bw); */ bool browser_window_history_forward_available(struct browser_window *bw); -/** - * Get the dimensions of a history. - * - * \param bw browser window with history object. - * \param width updated to width - * \param height updated to height - */ -void browser_window_history_size(struct browser_window *bw, - int *width, int *height); - -/** - * Redraw all of a history area. - * - * \param bw browser window with history object. - * \param ctx current redraw context - */ -bool browser_window_history_redraw(struct browser_window *bw, - const struct redraw_context *ctx); - -/** - * Redraw part of a history area. - * - * \param bw browser window with history object. - * \param x0 left X co-ordinate of redraw area - * \param y0 top Y co-ordinate of redraw area - * \param x1 right X co-ordinate of redraw area - * \param y1 lower Y co-ordinate of redraw area - * \param x start X co-ordinate on plot canvas - * \param y start Y co-ordinate on plot canvas - * \param ctx current redraw context - */ -bool browser_window_history_redraw_rectangle(struct browser_window *bw, - int x0, int y0, int x1, int y1, int x, int y, - const struct redraw_context *ctx); - -/** - * Handle a mouse click in a history. - * - * \param bw browser window containing history - * \param x click coordinate - * \param y click coordinate - * \param new_window open a new window instead of using bw - * \return true if action was taken, false if click was not on an entry - */ -bool browser_window_history_click(struct browser_window *bw, - int x, int y, bool new_window); - -/** - * Determine the URL of the entry at a position. - * - * \param bw browser window containing history - * \param x x coordinate. - * \param y y coordinate. - * \return URL, or 0 if no entry at (x, y) - */ -const char *browser_window_history_position_url(struct browser_window *bw, - int x, int y); /** * Callback function type for history enumeration @@ -187,6 +89,7 @@ typedef bool (*browser_window_history_enumerate_cb)( int x0, int y0, int x1, int y1, const struct history_entry *entry, void *user_data); + /** * Enumerate all entries in the history. * Do not change the history while it is being enumerated. @@ -198,6 +101,7 @@ typedef bool (*browser_window_history_enumerate_cb)( void browser_window_history_enumerate(const struct browser_window *bw, browser_window_history_enumerate_cb cb, void *user_data); + /** * Enumerate all entries that will be reached by the 'forward' button * @@ -208,6 +112,7 @@ void browser_window_history_enumerate(const struct browser_window *bw, void browser_window_history_enumerate_forward(const struct browser_window *bw, browser_window_history_enumerate_cb cb, void *user_data); + /** * Enumerate all entries that will be reached by the 'back' button * @@ -218,14 +123,15 @@ void browser_window_history_enumerate_forward(const struct browser_window *bw, void browser_window_history_enumerate_back(const struct browser_window *bw, browser_window_history_enumerate_cb cb, void *user_data); + /** * Returns the URL to a history entry * - * \param entry the history entry to retrieve the URL from - * \return the URL + * \param entry the history entry to retrieve the URL from + * \return A referenced nsurl URL */ -const char *browser_window_history_entry_get_url( - const struct history_entry *entry); +struct nsurl *browser_window_history_entry_get_url(const struct history_entry *entry); + /** * Returns the URL to a history entry @@ -236,6 +142,7 @@ const char *browser_window_history_entry_get_url( const char *browser_window_history_entry_get_fragment_id( const struct history_entry *entry); + /** * Returns the title of a history entry * @@ -245,6 +152,7 @@ const char *browser_window_history_entry_get_fragment_id( const char *browser_window_history_entry_get_title( const struct history_entry *entry); + /** * Navigate to specified history entry, optionally in new window * diff --git a/desktop/browser_private.h b/desktop/browser_private.h index 5a53e2f0b..8bbc573eb 100644 --- a/desktop/browser_private.h +++ b/desktop/browser_private.h @@ -35,8 +35,48 @@ struct box; struct hlcache_handle; struct gui_window; -struct history; struct selection; +struct nsurl; + +/** + * history entry page information + */ +struct history_page { + struct nsurl *url; /**< Page URL, never NULL. */ + lwc_string *frag_id; /** Fragment identifier, or NULL. */ + char *title; /**< Page title, never NULL. */ +}; + +/** + * A node in the history tree. + */ +struct history_entry { + struct history_page page; + struct history_entry *back; /**< Parent. */ + struct history_entry *next; /**< Next sibling. */ + struct history_entry *forward; /**< First child. */ + struct history_entry *forward_pref; /**< Child in direction of + current entry. */ + struct history_entry *forward_last; /**< Last child. */ + unsigned int children; /**< Number of children. */ + int x; /**< Position of node. */ + int y; /**< Position of node. */ + struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */ +}; + +/** + * History tree for a window. + */ +struct history { + /** First page in tree (page that window opened with). */ + struct history_entry *start; + /** Current position in tree. */ + struct history_entry *current; + /** Width of layout. */ + int width; + /** Height of layout. */ + int height; +}; /** * Browser window data. @@ -249,4 +289,57 @@ void browser_window_set_status(struct browser_window *bw, const char *text); */ struct browser_window * browser_window_get_root(struct browser_window *bw); + +/** + * Create a new history tree for a browser window window. + * + * \param bw browser window to create history for. + * + * \return NSERROR_OK or appropriate error otherwise + */ +nserror browser_window_history_create(struct browser_window *bw); + +/** + * Clone a bw's history tree for new bw + * + * \param existing browser window with history to clone. + * \param clone browser window to make cloned history for. + * + * \return NSERROR_OK or appropriate error otherwise + */ +nserror browser_window_history_clone(const struct browser_window *existing, + struct browser_window *clone); + + +/** + * Insert a url into the history tree. + * + * \param bw browser window with history object + * \param content content to add to history + * \param frag_id fragment identifier, or NULL. + * \return NSERROR_OK or error code on faliure. + * + * The page is added after the current entry and becomes current. + */ +nserror browser_window_history_add(struct browser_window *bw, + struct hlcache_handle *content, lwc_string *frag_id); + +/** + * Update the thumbnail for the current entry. + * + * \param bw The browser window to update the history within. + * \param content content for current entry + * \return NSERROR_OK or error code on faliure. + */ +nserror browser_window_history_update(struct browser_window *bw, + struct hlcache_handle *content); + +/** + * Free a history structure. + * + * \param bw The browser window to destroy the history within. + */ +void browser_window_history_destroy(struct browser_window *bw); + + #endif diff --git a/desktop/local_history.c b/desktop/local_history.c index 6d07c8ad7..01222e204 100644 --- a/desktop/local_history.c +++ b/desktop/local_history.c @@ -22,28 +22,272 @@ */ #include <stdlib.h> +#include <string.h> #include "utils/errors.h" +#include "utils/nsurl.h" #include "netsurf/types.h" +#include "netsurf/layout.h" #include "netsurf/core_window.h" +#include "netsurf/plotters.h" +#include "desktop/gui_internal.h" +#include "desktop/system_colour.h" +#include "desktop/browser_private.h" #include "desktop/browser_history.h" #include "desktop/local_history.h" +#define WIDTH 100 +#define HEIGHT 86 + +/** + * local history viewer context + */ struct local_history_session { struct browser_window *bw; struct core_window_callback_table *cw_t; void *core_window_handle; }; + +/** + * plot style for drawing lines between nodes + */ +static plot_style_t pstyle_line = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = 2, +}; + + +/** + * plot style for drawing background + */ +static plot_style_t pstyle_bg = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; + + +/** + * plot style for drawing rectangle round unselected nodes + */ +static plot_style_t pstyle_rect = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = 1, +}; + + +/** + * plot style for drawing rectangle round selected nodes + */ +static plot_style_t pstyle_rect_sel = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_width = 3, +}; + + +/** + * plot style for font on unselected nodes + */ +static plot_font_style_t pfstyle_node = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 8 * FONT_SIZE_SCALE, + .weight = 400, + .flags = FONTF_NONE, +}; + + +/** + * plot style for font on unselected nodes + */ +static plot_font_style_t pfstyle_node_sel = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 8 * FONT_SIZE_SCALE, + .weight = 900, + .flags = FONTF_NONE, +}; + + +/** + * Recursively redraw a history entry. + * + * \param history history containing the entry + * \param entry entry to render + * \param clip redraw area + * \param x window x offset + * \param y window y offset + * \param ctx current redraw context + */ +static nserror +redraw_entry(struct history *history, + struct history_entry *entry, + struct rect *clip, + int x, int y, + const struct redraw_context *ctx) +{ + size_t char_offset; + int actual_x; + struct history_entry *child; + int tailsize = 5; + + plot_style_t *pstyle; + plot_font_style_t *pfstyle; + struct rect rect; + nserror res; + + /* setup plot styles */ + if (entry == history->current) { + pstyle = &pstyle_rect_sel; + pfstyle = &pfstyle_node_sel; + } else { + pstyle = &pstyle_rect; + pfstyle = &pfstyle_node; + } + + /* Only attempt to plot bitmap if it is present */ + if (entry->bitmap != NULL) { + res = ctx->plot->bitmap(ctx, + entry->bitmap, + entry->x + x, + entry->y + y, + WIDTH, HEIGHT, + 0xffffff, + 0); + if (res != NSERROR_OK) { + return res; + } + } + + rect.x0 = entry->x - 1 + x; + rect.y0 = entry->y - 1 + y; + rect.x1 = entry->x + x + WIDTH; + rect.y1 = entry->y + y + HEIGHT; + res = ctx->plot->rectangle(ctx, pstyle, &rect); + if (res != NSERROR_OK) { + return res; + } + + res = guit->layout->position(plot_style_font, entry->page.title, + strlen(entry->page.title), WIDTH, + &char_offset, &actual_x); + if (res != NSERROR_OK) { + return res; + } + + res = ctx->plot->text(ctx, + pfstyle, + entry->x + x, + entry->y + HEIGHT + 12 + y, + entry->page.title, + char_offset); + if (res != NSERROR_OK) { + return res; + } + + /* for each child node draw a line and recurse redraw into it */ + for (child = entry->forward; child; child = child->next) { + rect.x0 = entry->x + WIDTH + x; + rect.y0 = entry->y + HEIGHT / 2 + y; + rect.x1 = entry->x + WIDTH + tailsize + x; + rect.y1 = entry->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + rect.x0 = entry->x + WIDTH + tailsize + x; + rect.y0 = entry->y + HEIGHT / 2 + y; + rect.x1 = child->x - tailsize + x; + rect.y1 = child->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + rect.x0 = child->x - tailsize + x; + rect.y0 = child->y + HEIGHT / 2 + y; + rect.x1 = child->x + x; + rect.y1 = child->y + HEIGHT / 2 + y; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { + return res; + } + + res = redraw_entry(history, child, clip, x, y, ctx); + if (res != NSERROR_OK) { + return res; + } + } + + return NSERROR_OK; +} + + +/** + * Find the history entry at a position. + * + * \param entry entry to search from + * \param x coordinate + * \param y coordinate + * \return an entry if found, 0 if none + */ +static struct history_entry * +find_entry_position(struct history_entry *entry, int x, int y) +{ + struct history_entry *child; + struct history_entry *found; + + if (!entry) { + return NULL; + } + + if ((entry->x <= x) && + (x <= entry->x + WIDTH) && + (entry->y <= y) && + (y <= entry->y + HEIGHT)) { + return entry; + } + + for (child = entry->forward; child; child = child->next) { + found = find_entry_position(child, x, y); + if (found) { + return found; + } + } + + return NULL; +} + + /* exported interface documented in desktop/local_history.h */ -nserror local_history_init(struct core_window_callback_table *cw_t, - void *core_window_handle, - struct browser_window *bw, - struct local_history_session **session) +nserror +local_history_init(struct core_window_callback_table *cw_t, + void *core_window_handle, + struct browser_window *bw, + struct local_history_session **session) { + nserror res; struct local_history_session *nses; + res = ns_system_colour_char("Window", &pstyle_bg.fill_colour); + if (res != NSERROR_OK) { + return res; + } + pfstyle_node.background = pstyle_bg.fill_colour; + pfstyle_node_sel.background = pstyle_bg.fill_colour; + + res = ns_system_colour_char("GrayText", &pstyle_line.stroke_colour); + if (res != NSERROR_OK) { + return res; + } + pstyle_rect.stroke_colour = pstyle_line.stroke_colour; + pfstyle_node.foreground = pstyle_line.stroke_colour; + + res = ns_system_colour_char("Highlight", &pstyle_rect_sel.stroke_colour); + if (res != NSERROR_OK) { + return res; + } + pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour; + nses = calloc(1, sizeof(struct local_history_session)); if (nses == NULL) { return NSERROR_NOMEM; @@ -55,6 +299,7 @@ nserror local_history_init(struct core_window_callback_table *cw_t, local_history_set(nses, bw); *session = nses; + return NSERROR_OK; } @@ -75,26 +320,69 @@ local_history_redraw(struct local_history_session *session, struct rect *clip, const struct redraw_context *ctx) { - if (session->bw != NULL) { - browser_window_history_redraw_rectangle(session->bw, - clip->x0, clip->y0, clip->x1, clip->y1, x, y, ctx); + struct rect r = { + .x0 = clip->x0 + x, + .y0 = clip->y0 + y, + .x1 = clip->x1 + x, + .y1 = clip->y1 + y, + }; + + if (session->bw == NULL) { + return NSERROR_OK; } - return NSERROR_OK; + + if (session->bw->history->start == NULL) { + return NSERROR_OK; + } + + ctx->plot->clip(ctx, &r); + ctx->plot->rectangle(ctx, &pstyle_bg, &r); + + return redraw_entry(session->bw->history, + session->bw->history->start, + clip, + x, y, + ctx); } /* exported interface documented in desktop/local_history.h */ -void +nserror local_history_mouse_action(struct local_history_session *session, enum browser_mouse_state mouse, int x, int y) { + struct history_entry *entry; + bool new_window; + + if (session->bw == NULL) { + return NSERROR_BAD_PARAMETER; + } + + if ((mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) == 0) { + return NSERROR_NOT_IMPLEMENTED; + } + + entry = find_entry_position(session->bw->history->start, x, y); + if (entry == NULL) { + return NSERROR_NOT_FOUND; + } + + if (entry == session->bw->history->current) { + return NSERROR_PERMISSION; + } + if (mouse & BROWSER_MOUSE_PRESS_1) { - browser_window_history_click(session->bw, x, y, false); - } else if (mouse & BROWSER_MOUSE_PRESS_2) { - browser_window_history_click(session->bw, x, y, true); + new_window = false; + } else if (mouse & BROWSER_MOUSE_PRESS_2) { + new_window = true; + } else { + new_window = false; } + browser_window_history_go(session->bw, entry, new_window); + + return NSERROR_OK; } /* exported interface documented in desktop/local_history.h */ @@ -109,15 +397,13 @@ nserror local_history_set(struct local_history_session *session, struct browser_window *bw) { - int width; - int height; - session->bw = bw; if (bw != NULL) { - browser_window_history_size(session->bw, &width, &height); + assert(session->bw->history != NULL); session->cw_t->update_size(session->core_window_handle, - width, height); + session->bw->history->width, + session->bw->history->height); } return NSERROR_OK; @@ -130,10 +416,8 @@ local_history_get_size(struct local_history_session *session, int *width, int *height) { - - browser_window_history_size(session->bw, width, height); - *width += 20; - *height += 20; + *width = session->bw->history->width + 20; + *height = session->bw->history->height + 20; return NSERROR_OK; } @@ -143,15 +427,20 @@ local_history_get_size(struct local_history_session *session, nserror local_history_get_url(struct local_history_session *session, int x, int y, - const char **url_out) + nsurl **url_out) { - const char *url; - url = browser_window_history_position_url(session->bw, x, y); - if (url == NULL) { + struct history_entry *entry; + + if (session->bw == NULL) { + return NSERROR_BAD_PARAMETER; + } + + entry = find_entry_position(session->bw->history->start, x, y); + if (entry == NULL) { return NSERROR_NOT_FOUND; } - *url_out = url; + *url_out = nsurl_ref(entry->page.url); return NSERROR_OK; } diff --git a/desktop/local_history.h b/desktop/local_history.h index 2ce2a5c22..7f85a633e 100644 --- a/desktop/local_history.h +++ b/desktop/local_history.h @@ -35,14 +35,15 @@ struct browser_window; /** * Initialise the local history. * - * This iterates through the URL database, generating the local history data, - * and creates a treeview. + * This iterates through the history object of a browser window and + * creates tree of visited pages with thumbnails which may be selected + * to cause navigation. * * This must be called before any other local_history_* function. * - * \param cw_t Callback table for core_window containing the treeview. - * \param core_window_handle The core_window in which the treeview is shown. - * \param bw browser window to show history of. + * \param[in] cw_t Callback table for core_window containing the treeview. + * \param[in] core_window_handle The core_window in which the treeview is shown. + * \param[in] bw browser window to show history of. * \param[out] session The created local history session context. * \return NSERROR_OK on success and session set, appropriate error code otherwise */ @@ -54,12 +55,12 @@ nserror local_history_init(struct core_window_callback_table *cw_t, /** * Finalise the local history. * - * This destroys the local history treeview and the local history module's - * internal data. After calling this if ocall history is required again, - * local_history_init must be called. + * This destroys the local history view and the local history module's + * internal data. After calling this if local history is required again, + * local_history_init must be called to create a new session. * * \param session The local history session to finalise. - * \return NSERROR_OK on success, appropriate error otherwise + * \return NSERROR_OK on success and session freed appropriate error otherwise */ nserror local_history_fini(struct local_history_session *session); @@ -67,42 +68,53 @@ nserror local_history_fini(struct local_history_session *session); /** * Redraw the local history. * - * \param session The local history session context. - * \param x X coordinate to render history at - * \param y Y coordinate to render history at - * \param clip Current clip rectangle (wrt tree origin) - * \param ctx Current redraw context + * Causes the local history viewer to issue plot operations to redraw + * the specified area of the viewport. + * + * \param[in] session The local history session context. + * \param[in] x X coordinate to render history at + * \param[in] y Y coordinate to render history at + * \param[in] clip Current clip rectangle (wrt tree origin) + * \param[in] ctx Current redraw context */ nserror local_history_redraw(struct local_history_session *session, int x, int y, struct rect *clip, const struct redraw_context *ctx); + /** * Handles all kinds of mouse action * - * \param session The local history session context. - * \param mouse The current mouse state - * \param x X coordinate - * \param y Y coordinate + * \param[in] session The local history session context. + * \param[in] mouse The current mouse state + * \param[in] x The current mouse X coordinate + * \param[in] y The current mouse Y coordinate + * \return NSERROR_OK if mouse action was processed. + * NSERROR_NOT_FOUND if nothing under the pointer where it was clicked + * NSERROR_NOT_IMPLEMENTED if the action was not processed. + * NSERROR_PERMISSION if the clicked item was the current page */ -void local_history_mouse_action(struct local_history_session *session, enum browser_mouse_state mouse, int x, int y); +nserror local_history_mouse_action(struct local_history_session *session, enum browser_mouse_state mouse, int x, int y); + /** * Key press handling. * - * \param session The local history session context. - * \param key The ucs4 character codepoint + * \param[in] session The local history session context. + * \param[in] key The ucs4 character codepoint * \return true if the keypress is dealt with, false otherwise. */ bool local_history_keypress(struct local_history_session *session, uint32_t key); + /** * Change the browser window to draw local history for. * - * \param session The local history session context. + * \param[in] session The local history session context. * \param bw browser window to show history of. * \return NSERROR_OK or appropriate error code. */ nserror local_history_set(struct local_history_session *session, struct browser_window *bw); + /** * get size of local history content area. * @@ -113,6 +125,7 @@ nserror local_history_set(struct local_history_session *session, struct browser_ */ nserror local_history_get_size(struct local_history_session *session, int *width, int *height); + /** * get url of entry at position in local history content area. * @@ -121,10 +134,11 @@ nserror local_history_get_size(struct local_history_session *session, int *width * \param[in] session The local history session context. * \param[in] x The x coordinate to get url of. * \param[in] y The y coordinate to get url of. - * \param[out] url_out string representation of the url at the coordinates. + * \param[out] url_out referenced url. * \return NSERROR_OK and url_out updated or NSERROR_NOT_FOUND if no url at * location. */ -nserror local_history_get_url(struct local_history_session *session, int x, int y, const char **url_out); +nserror local_history_get_url(struct local_history_session *session, int x, int y, struct nsurl **url_out); + #endif diff --git a/desktop/scrollbar.h b/desktop/scrollbar.h index f7153318f..fa5e167f2 100644 --- a/desktop/scrollbar.h +++ b/desktop/scrollbar.h @@ -19,6 +19,8 @@ /** * \file * Scrollbar widget interface. + * + * Scrollbar widgets used in frames code, not for frontend use */ #ifndef NETSURF_DESKTOP_SCROLLBAR_H @@ -30,10 +32,10 @@ #define SCROLLBAR_WIDTH 16 /* Region dependent values for scrollbar_scroll function */ -#define SCROLL_TOP INT_MIN -#define SCROLL_PAGE_UP INT_MIN + 1 -#define SCROLL_PAGE_DOWN INT_MAX - 1 -#define SCROLL_BOTTOM INT_MAX +#define SCROLL_TOP INT_MIN +#define SCROLL_PAGE_UP (INT_MIN + 1) +#define SCROLL_PAGE_DOWN (INT_MAX - 1) +#define SCROLL_BOTTOM INT_MAX struct scrollbar; diff --git a/Docs/Doxyfile b/docs/Doxyfile index f3fdd1ef1..e549981bd 100644 --- a/Docs/Doxyfile +++ b/docs/Doxyfile @@ -753,7 +753,10 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = frontends/amiga \ +INPUT = docs \ + docs/env.sh \ + docs/UnimplementedJavascript.txt \ + frontends/amiga \ frontends/amiga/stringview \ frontends/atari \ frontends/atari/plot \ @@ -780,8 +783,7 @@ INPUT = frontends/amiga \ content/handlers/javascript \ content/handlers/javascript/duktape \ utils \ - utils/http \ - Docs/UnimplementedJavascript.txt + utils/http # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -806,7 +808,8 @@ FILE_PATTERNS = *.c \ *.y \ *.l \ *.cpp \ - *.m + *.m \ + *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -922,7 +925,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = mainpage.md #--------------------------------------------------------------------------- # Configuration options related to source browsing diff --git a/Docs/PACKAGING-GTK b/docs/PACKAGING-GTK index 8f675229f..8f675229f 100644 --- a/Docs/PACKAGING-GTK +++ b/docs/PACKAGING-GTK diff --git a/Docs/UnimplementedJavascript.txt b/docs/UnimplementedJavascript.txt index 1b851b8bb..1b851b8bb 100644 --- a/Docs/UnimplementedJavascript.txt +++ b/docs/UnimplementedJavascript.txt diff --git a/Docs/BUILDING-AmigaCross b/docs/building-AmigaCross.md index 32762cd5b..32762cd5b 100644 --- a/Docs/BUILDING-AmigaCross +++ b/docs/building-AmigaCross.md diff --git a/Docs/BUILDING-AmigaOS b/docs/building-AmigaOS.md index 3f05b9caf..3f05b9caf 100644 --- a/Docs/BUILDING-AmigaOS +++ b/docs/building-AmigaOS.md diff --git a/Docs/BUILDING-Framebuffer b/docs/building-Framebuffer.md index 3c8858a32..3c8858a32 100644 --- a/Docs/BUILDING-Framebuffer +++ b/docs/building-Framebuffer.md diff --git a/Docs/BUILDING-GTK b/docs/building-GTK.md index 4ac0fc89e..4ac0fc89e 100644 --- a/Docs/BUILDING-GTK +++ b/docs/building-GTK.md diff --git a/Docs/BUILDING-BeOS b/docs/building-Haiku.md index 8642861d3..8642861d3 100644 --- a/Docs/BUILDING-BeOS +++ b/docs/building-Haiku.md diff --git a/Docs/BUILDING-Windows b/docs/building-Windows.md index dc6769fdf..dc6769fdf 100644 --- a/Docs/BUILDING-Windows +++ b/docs/building-Windows.md diff --git a/docs/core-window-interface.md b/docs/core-window-interface.md new file mode 100644 index 000000000..8f6951f9f --- /dev/null +++ b/docs/core-window-interface.md @@ -0,0 +1,677 @@ +Core Window Interface +===================== + +The NetSurf core provides an optional API to frontend implementations +which allows a number of "standard" window content interfaces to be +provided. + +The currently available user interfaces are: + + - Cookies + - Global history + - Hotlist + - SSL certificate view + - local history + +Although not currently included in future additional user interfaces +will be available for the main browser render. + +To be clear these are generic implementations of this functionality +that any frontend may use. Frontends are free to implement these +interfaces in any manner as they see fit, the corewindow interface +simply provides a default. + +core window API +--------------- + +The API is fairly simple and simply involves passing a callback table +and context pointer to the interface element being constructed. + +The header that defines the callback interface is netsurf/core_window.h + +The callback table contains five function pointer interfaces which the +frontend must implement for the core. + + - invalidate + invalidate an area of a window + + - update_size + Update the limits of the window + + - scroll_visible + Scroll the window to make area visible + + - get_window_dimensions + Get window viewport dimensions + + - drag_status + Inform corewindow owner of drag status + +Each callback will be passed the context pointer for the corewindow +instance and the relevant additional information necessary to perform +the operation. + +Each exported user interface element wraps this generic interface with +a concrete implementation. For example the SSL certificate viewer is +initialised with: + + nserror sslcert_viewer_init(struct core_window_callback_table *cw_t, + void *core_window_handle, + struct sslcert_session_data *ssl_d); + +This call creates a context which will display and navigate the ssl +session data passed. The frontend must service the callbacks from the +core to provide the necessary interactions with the frontend windowing +system. + +These actions should ideally use the standard frontend window +processing. So for the GTK frontend when the core calls the invalidate +operation it simply marks the area passed as damaged (using +gtk_widget_queue_draw_area()) and lets the standard expose event cause +the redraw to occur. + +If the frontend needs to redraw an area of a window (perhaps an expose +event occurred or the window has had an area marked as invalid) it +must call the core window API wrappers implementation which will +perform the plot operations required to update an area of the window. + +e.g in the case of ssl certificate viewer + + void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d, + int x, int y, struct rect *clip, + const struct redraw_context *ctx); + +would perform the plot operations for that SSL data window. + +Usage +----- + +The usage pattern that is expected is for a frontend to create a core +window implementation that implements the necessary five API in a +generic way and allows the frontend to provide the specific +specialisation for each of the user interface elements it wishes to +use (cookies, SSL viewer etc). + +The GTK frontend for example: + +has source corewindow.[ch] which implement the five core callbacks +using generic GTK operations (invalidate calls +gtk_widget_queue_draw_area() etc.) and then provides additional +operations on a GTK drawing area object to attach expose event +processing, keypress processing etc. + +The GTK corewindow (not to be confused with the core window API +itself, this is purely the gtk wrapper) is used by ssl_cert.c which +creates a nsgtk_crtvrfy_window structure containing the +nsgtk_corewindow structure. It attaches actual GTK window handles to +this structure and populates elements of nsgtk_corewindow and then +calls sslcert_viewer_init() directly. + +frontend skeleton +----------------- + +An example core window implementation for a frontend ssl certificate +viewer is presented here. This implements the suggested usage above +and provides generic corewindow helpers. + + +frontends/example/corewindow.h +------------------------------ + + /* + * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + #ifndef EXAMPLE_COREWINDOW_H + #define EXAMPLE_COREWINDOW_H + + #include "netsurf/core_window.h" + + /** + * example core window state + */ + struct example_corewindow { + + + /* + * Any variables common to any frontend window would go here. + * e.g. drawing area handles, toolkit pointers or other state + */ + example_toolkit_widget *tk_widget; + + + + /** drag status set by core */ + core_window_drag_status drag_status; + + /** table of callbacks for core window operations */ + struct core_window_callback_table *cb_table; + + /** + * callback to draw on drawable area of example core window + * + * \param example_cw The example core window structure. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise apropriate error code + */ + nserror (*draw)(struct example_corewindow *example_cw, struct rect *r); + + /** + * callback for keypress on example core window + * + * \param example_cw The example core window structure. + * \param nskey The netsurf key code. + * \return NSERROR_OK if key processed, + * NSERROR_NOT_IMPLEMENTED if key not processed + * otherwise apropriate error code + */ + nserror (*key)(struct example_corewindow *example_cw, uint32_t nskey); + + /** + * callback for mouse event on example core window + * + * \param example_cw The example core window structure. + * \param mouse_state mouse state + * \param x location of event + * \param y location of event + * \return NSERROR_OK on sucess otherwise apropriate error code. + */ + nserror (*mouse)(struct example_corewindow *example_cw, browser_mouse_state mouse_state, int x, int y); + }; + + /** + * initialise elements of example core window. + * + * As a pre-requisite the draw, key and mouse callbacks must be defined + * + * \param example_cw A example core window structure to initialise + * \return NSERROR_OK on successful initialisation otherwise error code. + */ + nserror example_corewindow_init(struct example_corewindow *example_cw); + + /** + * finalise elements of example core window. + * + * \param example_cw A example core window structure to initialise + * \return NSERROR_OK on successful finalisation otherwise error code. + */ + nserror example_corewindow_fini(struct example_corewindow *example_cw); + + #endif + +frontends/example/corewindow.c +------------------------------ + + /* + * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + /** + * file + * EXAMPLE generic core window interface. + * + * Provides interface for core renderers to the example toolkit drawable area. + * + * This module is an object that must be encapsulated. Client users + * should embed a struct example_corewindow at the beginning of their + * context for this display surface, fill in relevant data and then + * call example_corewindow_init() + * + * The example core window structure requires the callback for draw, key and + * mouse operations. + */ + + #include <assert.h> + #include <string.h> + #include <math.h> + + #include "utils/log.h" + #include "utils/utils.h" + #include "utils/messages.h" + #include "utils/utf8.h" + #include "netsurf/keypress.h" + #include "netsurf/mouse.h" + #include "netsurf/plot_style.h" + + /* extremely likely there will be additional headers required in a real frontend */ + #include "example/corewindow.h" + + + /* toolkit event handlers that do generic things and call internal callbacks */ + + + static bool + example_cw_mouse_press_event(toolkit_widget *widget, toolkit_button bt, int x, int y, void *ctx) + { + struct example_corewindow *example_cw = (struct example_corewindow *)ctx; + + example_cw->mouse(example_cw, state, x, y); + + return true; + } + + static bool + example_cw_keyrelease_event(toolkit_widget *widget, void *ctx) + { + struct example_corewindow *example_cw = (struct example_corewindow *)ctx; + + example_cw->key(example_cw, keycode); + + return true; + } + + + + /* signal handler for toolkit window redraw */ + static bool + example_cw_draw_event(toolkit_widget *widget, + toolkit_area *tk_area, + void *ctx) + { + struct example_corewindow *example_cw = (struct example_corewindow *)ctx; + struct rect clip; + + clip.x0 = tk_area.x; + clip.y0 = tk_area.y; + clip.x1 = tk_area.width; + clip.y1 = tk_area.height; + + example_cw->draw(example_cw, &clip); + + return true; + } + + + /** + * callback from core to request a redraw + */ + static nserror + example_cw_invalidate(struct core_window *cw, const struct rect *r) + { + struct example_corewindow *example_cw = (struct example_corewindow *)cw; + + toolkit_widget_queue_draw_area(example_cw->widget, + r->x0, r->y0, + r->x1 - r->x0, r->y1 - r->y0); + } + + + static void + example_cw_update_size(struct core_window *cw, int width, int height) + { + struct example_corewindow *example_cw = (struct example_corewindow *)cw; + + toolkit_widget_set_size_request(EXAMPLE_WIDGET(example_cw->drawing_area), + width, height); + } + + + static void + example_cw_scroll_visible(struct core_window *cw, const struct rect *r) + { + struct example_corewindow *example_cw = (struct example_corewindow *)cw; + + toolkit_scroll_widget(example_cw->widget, r); + } + + + static void + example_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) + { + struct example_corewindow *example_cw = (struct example_corewindow *)cw; + + *width = toolkit_get_widget_width(example_cw->widget); + *height = toolkit_get_widget_height(example_cw->widget); + } + + + static void + example_cw_drag_status(struct core_window *cw, core_window_drag_status ds) + { + struct example_corewindow *example_cw = (struct example_corewindow *)cw; + example_cw->drag_status = ds; + } + + + struct core_window_callback_table example_cw_cb_table = { + .invalidate = example_cw_invalidate, + .update_size = example_cw_update_size, + .scroll_visible = example_cw_scroll_visible, + .get_window_dimensions = example_cw_get_window_dimensions, + .drag_status = example_cw_drag_status + }; + + /* exported function documented example/corewindow.h */ + nserror example_corewindow_init(struct example_corewindow *example_cw) + { + /* setup the core window callback table */ + example_cw->cb_table = &example_cw_cb_table; + + /* frontend toolkit specific method of causing example_cw_draw_event to be called when a drawing operation is required */ + toolkit_connect_draw_event(example_cw->tk_widget, + example_cw_draw_event, + example_cw); + + /* frontend toolkit specific method of causing example_cw_button_press_event to be called when a button press occours */ + toolkit_connect_button_press_event(example_cw->tk_widget, + example_cw_button_press_event, + example_cw); + + /* frontend toolkit specific method of causing example_cw_button_release_event to be called when a button release occours */ + toolkit_connect_button_release_event(example_cw->tk_widget, + example_cw_button_release_event, + example_cw); + + /* frontend toolkit specific method of causing example_cw_motion_notify_event to be called when there is motion over the widget */ + toolkit_connect_motion_event(example_cw->tk_widget, + example_cw_motion_notify_event, + example_cw); + + /* frontend toolkit specific method of causing example_cw_key_press_event to be called when a key press occours */ + toolkit_connect_button_press_event(example_cw->tk_widget, + example_cw_key_press_event, + example_cw); + + /* frontend toolkit specific method of causing example_cw_key_release_event to be called when a key release occours */ + toolkit_connect_button_release_event(example_cw->tk_widget, + example_cw_key_release_event, + example_cw); + + + return NSERROR_OK; + } + + /* exported interface documented in example/corewindow.h */ + nserror example_corewindow_fini(struct example_corewindow *example_cw) + { + return NSERROR_OK; + } + + +frontends/example/ssl_cert.h +---------------------------- + + /* + * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + #ifndef NETSURF_EXAMPLE_SSL_CERT_H + #define NETSURF_EXAMPLE_SSL_CERT_H 1 + + struct nsurl; + struct ssl_cert_info; + + /** + * Prompt the user to verify a certificate with issuse. + * + * \param url The URL being verified. + * \param certs The certificate to be verified + * \param num The number of certificates to be verified. + * \param cb Callback upon user decision. + * \param cbpw Context pointer passed to cb + * \return NSERROR_OK or error code if prompt creation failed. + */ + nserror example_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw); + + #endif + +frontends/example/ssl_cert.c +---------------------------- + + /* + * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + /** + * file + * Implementation of example certificate viewing using example core windows. + */ + + #include <stdint.h> + #include <stdlib.h> + + #include "utils/log.h" + #include "netsurf/keypress.h" + #include "netsurf/plotters.h" + #include "desktop/sslcert_viewer.h" + + #include "example/corewindow.h" + + + /** + * EXAMPLE certificate viewing window context + */ + struct example_crtvrfy_window { + /** example core window context */ + struct example_corewindow core; + + /** SSL certificate viewer context data */ + struct sslcert_session_data *ssl_data; + }; + + /** + * destroy a previously created certificate view + */ + static nserror example_crtvrfy_destroy(struct example_crtvrfy_window *crtvrfy_win) + { + nserror res; + + res = sslcert_viewer_fini(crtvrfy_win->ssl_data); + if (res == NSERROR_OK) { + res = example_corewindow_fini(&crtvrfy_win->core); + toolkit_windown_destroy(crtvrfy_win->window); + free(crtvrfy_win); + } + return res; + } + + static void + example_crtvrfy_accept(ExampleButton *w, gpointer data) + { + struct example_crtvrfy_window *crtvrfy_win; + crtvrfy_win = (struct example_crtvrfy_window *)data; + + sslcert_viewer_accept(crtvrfy_win->ssl_data); + + example_crtvrfy_destroy(crtvrfy_win); + } + + static void + example_crtvrfy_reject(ExampleWidget *w, gpointer data) + { + struct example_crtvrfy_window *crtvrfy_win; + crtvrfy_win = (struct example_crtvrfy_window *)data; + + sslcert_viewer_reject(crtvrfy_win->ssl_data); + + example_crtvrfy_destroy(crtvrfy_win); + } + + + /** + * callback for mouse action for certificate verify on core window + * + * \param example_cw The example core window structure. + * \param mouse_state netsurf mouse state on event + * \param x location of event + * \param y location of event + * \return NSERROR_OK on success otherwise apropriate error code + */ + static nserror + example_crtvrfy_mouse(struct example_corewindow *example_cw, + browser_mouse_state mouse_state, + int x, int y) + { + struct example_crtvrfy_window *crtvrfy_win; + /* technically degenerate container of */ + crtvrfy_win = (struct example_crtvrfy_window *)example_cw; + + sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y); + + return NSERROR_OK; + } + + /** + * callback for keypress for certificate verify on core window + * + * \param example_cw The example core window structure. + * \param nskey The netsurf key code + * \return NSERROR_OK on success otherwise apropriate error code + */ + static nserror + example_crtvrfy_key(struct example_corewindow *example_cw, uint32_t nskey) + { + struct example_crtvrfy_window *crtvrfy_win; + + /* technically degenerate container of */ + crtvrfy_win = (struct example_crtvrfy_window *)example_cw; + + if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) { + return NSERROR_OK; + } + return NSERROR_NOT_IMPLEMENTED; + } + + /** + * callback on draw event for certificate verify on core window + * + * \param example_cw The example core window structure. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise apropriate error code + */ + static nserror + example_crtvrfy_draw(struct example_corewindow *example_cw, struct rect *r) + { + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &example_plotters + }; + struct example_crtvrfy_window *crtvrfy_win; + + /* technically degenerate container of */ + crtvrfy_win = (struct example_crtvrfy_window *)example_cw; + + sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx); + + return NSERROR_OK; + } + + /* exported interface documented in example/ssl_cert.h */ + nserror example_cert_verify(struct nsurl *url, + const struct ssl_cert_info *certs, + unsigned long num, + nserror (*cb)(bool proceed, void *pw), + void *cbpw) + { + struct example_crtvrfy_window *ncwin; + nserror res; + + ncwin = malloc(sizeof(struct example_crtvrfy_window)); + if (ncwin == NULL) { + return NSERROR_NOMEM; + } + + res = toolkit_create_window(&ncwin->window); + if (res != NSERROR_OK) { + LOG("SSL UI builder init failed"); + free(ncwin); + return res; + } + + /* store the widget that the toolkit is drawing into */ + ncwin->core.widget = toolkit_get_widget(ncwin->window, "SSLDrawingArea")); + + /* would typicaly setup toolkit accept/reject buttons etc. here */ + toolkit_connect_button_press(ncwin->tk_accept_button, + example_crtvrfy_accept, + ncwin); + + + /* initialise example core window */ + ncwin->core.draw = example_crtvrfy_draw; + ncwin->core.key = example_crtvrfy_key; + ncwin->core.mouse = example_crtvrfy_mouse; + + res = example_corewindow_init(&ncwin->core); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + /* initialise certificate viewing interface */ + res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, + &ncwin->ssl_data); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + res = sslcert_viewer_init(ncwin->core.cb_table, + (struct core_window *)ncwin, + ncwin->ssl_data); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + toolkit_widget_show(ncwin->window); + + return NSERROR_OK; + } diff --git a/Docs/env.sh b/docs/env.sh index 9cfc95650..518123e2f 100644 --- a/Docs/env.sh +++ b/docs/env.sh @@ -272,8 +272,8 @@ ns-clone() done # put current env.sh in place in workspace - if [ ! -f "${TARGET_WORKSPACE}/env.sh" -a -f ${TARGET_WORKSPACE}/${NS_BROWSER}/Docs/env.sh ]; then - cp ${TARGET_WORKSPACE}/${NS_BROWSER}/Docs/env.sh ${TARGET_WORKSPACE}/env.sh + if [ ! -f "${TARGET_WORKSPACE}/env.sh" -a -f ${TARGET_WORKSPACE}/${NS_BROWSER}/docs/env.sh ]; then + cp ${TARGET_WORKSPACE}/${NS_BROWSER}/docs/env.sh ${TARGET_WORKSPACE}/env.sh fi } diff --git a/Docs/gource.sh b/docs/gource.sh index a1fbcbe13..a1fbcbe13 100755 --- a/Docs/gource.sh +++ b/docs/gource.sh diff --git a/Docs/ideas/cache.txt b/docs/ideas/cache.txt index fda0617a3..fda0617a3 100644 --- a/Docs/ideas/cache.txt +++ b/docs/ideas/cache.txt diff --git a/Docs/ideas/css-engine.txt b/docs/ideas/css-engine.txt index 1ea8778d5..1ea8778d5 100644 --- a/Docs/ideas/css-engine.txt +++ b/docs/ideas/css-engine.txt diff --git a/Docs/ideas/render-library.txt b/docs/ideas/render-library.txt index db645c427..db645c427 100644 --- a/Docs/ideas/render-library.txt +++ b/docs/ideas/render-library.txt diff --git a/docs/mainpage.md b/docs/mainpage.md new file mode 100644 index 000000000..41f26d441 --- /dev/null +++ b/docs/mainpage.md @@ -0,0 +1,93 @@ +NetSurf web browser +=================== + +![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1037/badge)[*](https://bestpractices.coreinfrastructure.org/projects/1037) + +The NetSurf code makes use of Doxygen for code documentation. + +User Interface +-------------- + +There are some basic user guides for the +[framebuffer](docs/using-framebuffer.md) and +[monkey](docs/using-monkey.md) frontends. + +The [core user options](docs/netsurf-options.md) of the browser are +documented which are augmented by each frontend in a specific manner. + +Documented API +-------------- + +There are several documents which detail specific aspects of the +codebase and APIs. + +### Core window + +The [core window API](docs/core-window-interface.md) allows frontends +to use generic core code for user interface elements beyond the +browser render. + +### Source object caching + +The [source object caching](docs/source-object-backing-store.md) +provides a way for downloaded content to be kept on a persistent +storage medium such as hard disc to make future retrieval of that +content quickly. + +### Javascript + +JavaScript is provided by integrating the duktape library. There are [instructions](docs/updating-duktape.md) on how to update the library. + +A list of [unimplemented DOM and CSSOM methods](unimplemented.html) +is available outlining the remaining API that have to be implemented. + +Development +----------- + +Compiling a development edition of NetSurf requires a POSIX style +environment. Typically this means a Linux based system although Free +BSD, Open BSD, Mac OS X and Haiku all known to work. + +### Working with the team + +Generally it is sensible to check with the other developers if you are +planning to make a change to NetSurf intended to be merged. + +We are often about on the IRC channel but failing that the developer +mailing list is a good place to try. + +All the project sources are held in [public git repositories](http://source.netsurf-browser.org/) + +### Toolchains + +Compilation for non POSIX toolkits/frontends (e.g. RISC OS) generally +relies upon a cross compilation environment which is generated using +the makefiles found in our +[toolchains](http://source.netsurf-browser.org/toolchains.git/) +repository. These toolchains are built by the Continuous Integration +(CI) system and the +[results of the system](http://ci.netsurf-browser.org/builds/toolchains/) +are published as a convenience. + +### Quick setup + +The [quick start guide](docs/quick-start.md) can be used to get a +development environment setup quickly and uses the +[env.sh](env_8sh_source.html) script the core team utilises. + +### Manual setup + +The Manual environment setup and compilation method is covered by the +details in the [netsurf libraries](docs/netsurf-libraries.md) document +for the core libraries and then one of the building documents for the +specific frontend. + +- [Amiga Os cross](docs/building-AmigaCross.md) and [Amiga OS](docs/building-AmigaOS.md) +- [Framebuffer](docs/building-Framebuffer.md) +- [GTK](docs/building-GTK.md) +- [Haiku (BeOS)](docs/building-Haiku.md) +- [Windows Win32](docs/building-Windows.md) + +These documents are sometimes not completely up to +date and the env.sh script should be considered canonical. + diff --git a/Docs/netsurf-fb.1 b/docs/netsurf-fb.1 index e4c310075..e4c310075 100644 --- a/Docs/netsurf-fb.1 +++ b/docs/netsurf-fb.1 diff --git a/Docs/netsurf-gtk.1 b/docs/netsurf-gtk.1 index 7b2f4f4f3..7b2f4f4f3 100644 --- a/Docs/netsurf-gtk.1 +++ b/docs/netsurf-gtk.1 diff --git a/Docs/LIBRARIES b/docs/netsurf-libraries.md index dc5a98048..dc5a98048 100644 --- a/Docs/LIBRARIES +++ b/docs/netsurf-libraries.md diff --git a/Docs/Options b/docs/netsurf-options.md index 89b881414..89b881414 100644 --- a/Docs/Options +++ b/docs/netsurf-options.md diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 000000000..8bc90de81 --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,111 @@ +Quick Build Steps for NetSurf +============================= + +Last Updated: 24 February 2015 + +This document provides steps for building NetSurf. + + +Grab a temporary env.sh +----------------------- + + $ wget http://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh + $ source env.sh + + +Install any packages you need +----------------------------- + +Installs all packages required to build NetSurf and the NetSurf project +libraries. + + $ ns-package-install + +If your package manager is not supported, you will have to install third + party packages manually. + + +Get the NetSurf project source code from Git +-------------------------------------------- + + $ ns-clone + + +Build and install our project libraries +--------------------------------------- + +Updates NetSurf project library sources to latest, builds and installs them. + + $ ns-pull-install + + +Switch to new NetSurf workspace +------------------------------- + +Remove the bootstrack script and use the newly installed one + + $ rm env.sh + $ cd ~/dev-netsurf/workspace + $ source env.sh + + +Build and run NetSurf +--------------------- + + $ cd netsurf + +To build the native front end (the GTK front end on Linux, BSDs, etc) you +could do: + + $ make + $ ./nsgtk + +To build the framebuffer front end, you could do: + + $ make TARGET=framebuffer + $ ./nsfb + + +Cross Compiling +=============== + +If you are cross compiling, you can follow the above steps, but when +sourcing env.sh, you should set HOST environment variable to the +appropriate triplet for your cross compiler. For example, to cross +compile for RISC OS: + + $ HOST=arm-unknown-riscos source env.sh + +After that, the commands such as `ns-package-install` and +`ns-pull-install` will do what is appropriate for the platform you +are building for. + +To do the final build of NetSurf, pass the appropriate TARGET to make. +For example, to cross compile for RISC OS: + + $ make TARGET=riscos + +Finally, you can package up your build to transfer to the system you +are developing for. For example, to produce a package for RISC OS: + + $ make TARGET=riscos package + +Getting a cross compiler set up +------------------------------- + +We maintain cross compilation environments and an SDK for a number of +platforms. These may be found in our toolchains repository. + + $ git clone git://git.netsurf-browser.org/toolchains + +Pre-built versions of the toolchains for Debian systems are often available +via our [automated build and test infrastructure](http://ci.netsurf-browser.org/builds/toolchains/) + + +Not working? +============ + +If the above steps are inapplicable, or don't work, you can build manually. +Follow the instructions in the BUILDING-* documents in the docs/ directory +the NetSurf browser source tree. + diff --git a/Docs/source-object-backing-store b/docs/source-object-backing-store.md index 0fb3614d4..0fb3614d4 100644 --- a/Docs/source-object-backing-store +++ b/docs/source-object-backing-store.md diff --git a/Docs/unit-testing b/docs/unit-testing index 49d82ed81..49d82ed81 100644 --- a/Docs/unit-testing +++ b/docs/unit-testing diff --git a/Docs/updating-duktape.md b/docs/updating-duktape.md index a3e5a79b1..672fccc89 100644 --- a/Docs/updating-duktape.md +++ b/docs/updating-duktape.md @@ -13,11 +13,11 @@ Updating Duktape 2. Run the following command: - python2 tools/configure.py \ - --output-directory /tmp/output \ - --source-directory src-input \ - --config-metadata config \ - --fixup-line '#include "duk_custom.h"' + python2 tools/configure.py \ + --output-directory /tmp/output \ + --source-directory src-input \ + --config-metadata config \ + --fixup-line '#include "duk_custom.h"' 3. This generates a suitable set of duktape sources in `/tmp/output` diff --git a/Docs/USING-Framebuffer b/docs/using-framebuffer.md index 3af8f983f..3af8f983f 100644 --- a/Docs/USING-Framebuffer +++ b/docs/using-framebuffer.md diff --git a/docs/using-monkey.md b/docs/using-monkey.md new file mode 100644 index 000000000..d6082bda9 --- /dev/null +++ b/docs/using-monkey.md @@ -0,0 +1,373 @@ +Usage Instructions for Monkey NetSurf +===================================== + +This document provides usage instructions for the Monkey version of NetSurf. + +Monkey NetSurf has been tested on Ubuntu and Debian. + +Overview +-------- + +### What it is + +The NetSurf Monkey front end is a developer debug tool used to test how the +core interacts with the user interface. It allows the developers to profile +NetSurf and to interact with the core directly as though the developer were a +front end. + +### What it is not + +Monkey is not a tool for building web-crawling robots or indeed anything other +than a debug tool for the NetSurf developers. + +### How to interact with `nsmonkey` + +In brief, `nsmonkey` will produce tagged output on stdout and expect +commands on stdin. Windows are numbered and for the most part +tokens are space separated. In some cases (e.g. title or status) +the final element on the output line is a string which might have +spaces embedded within it. As such, output from `nsmonkey` should be +parsed a token at a time, so that when such a string is encountered, +the parser can stop splitting and return the rest. + +Commands to `nsmonkey` are namespaced. For example commands related to +browser windows are prefixed by `WINDOW`. + +### Top level tags for `nsmonkey` + +* `QUIT` + +* `WINDOW` + +* `OPTIONS` + +### Top level response tags for nsmonkey + +* `GENERIC`: Generic messages such as poll loops etc. + +* `WARN`, `ERROR`, `DIE`: Error messages of varying importance + +* `WINDOW`: Anything about browser windows in general + +* `DOWNLOAD_WINDOW`: Anything about the download window. + +* `SSLCERT`: Anything about SSL certificates + +* `401LOGIN`: Anything about HTTP Basic Authentication logins + +* `PLOT`: Plot calls which come from the core. + +In the below, _%something%_ indicates a substitution made by Monkey. + +* _%url%_ will be a URL +* _%id%_ will be an opaque ID +* _%n%_ will be a number +* _%bool%_ will be TRUE or FALSE +* _%str%_ is a string and will only ever be at the end of an output line. + +### Warnings, errors etc + +* Warnings (tagged `WARN`) come from the NetSurf core. +* Errors (tagged `ERROR`) tend to come from Monkey's parsers +* Death (tagged `DIE`) comes from the core and kills Monkey dead. + +Commands +-------- + +### Generic commands + +* `QUIT` + + Cause monkey to quit cleanly. + This will cleanly destroy open windows etc. + +* `OPTIONS` _%str_ + + Cause monkey to set options. The passed options should be in the same + form as the command line, e.g. `OPTIONS --enable_javascript=1` + + +### Window commands + +* `WINDOW NEW` [_%url%_] + + Create a new browser window, optionally giving the core + a URL to immediately navigate to. + Minimally you will receive a `WINDOW NEW WIN` _%id%_ response. + +* `WINDOW DESTROY` _%id%_ + + Destroy the given browser window. + Minimally you will receive a `WINDOW DESTROY WIN` _%id%_ response. + +* `WINDOW GO` _%id%_ _%url%_ [_%url%_] + + Cause the given browser window to visit the given URL. + Optionally you can give a referrer URL to also use (simulating + a click in the browser on a link). + Minimally you can expect throbber, url etc responses. + +* `WINDOW REDRAW` _%id%_ [_%num% %num% %num% %num%_] + + Cause a browser window to redraw. Optionally you can give a + set of coordinates to simulate a partial expose of the window. + Said coordinates are in traditional X0 Y0 X1 Y1 order. + The coordinates are in canvas, not window, coordinates. So you + should take into account the scroll offsets when issuing this + command. + Minimally you can expect redraw start/stop messages and you + can likely expect some number of `PLOT` results. + +* `WINDOW RELOAD` _%id%_ + + Cause a browser window to reload its current content. + Expect responses similar to a GO command. + + +Responses +--------- + +### Generic messages + +* `GENERIC STARTED` + + Monkey has started and is ready for commands + +* `GENERIC CLOSING_DOWN` + + Monkey has been told to shut down and is doing so + +* `GENERIC FINISHED` + + Monkey has finished and will now exit + +* `GENERIC LAUNCH URL` _%url%_ + + The core asked monkey to launch the given URL + +* `GENERIC THUMBNAIL URL` _%url%_ + + The core asked monkey to thumbnail a content without + a window. + +* `GENERIC POLL BLOCKING` +* `GENERIC POLL TIMED` _%n%_ + + Monkey reached a point where it could sleep waiting for + commands or scheduled timeouts. No fetches nor redraws + were pending. If there are no timeouts or other pending + jobs then this will be a BLOCKING poll, otherwise the number + given is in milliseconds. + +### Window messages + +* `WINDOW NEW WIN` _%id%_ `FOR` _%id%_ `CLONE` _%id%_ `NEWTAB` _%bool%_ + + The core asked Monkey to open a new window. The IDs for `FOR` and + `CLONE` are core window IDs, the `WIN` id is a Monkey window ID. + +* `WINDOW SIZE WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_ + + The window specified has been set to the shown width and height. + +* `WINDOW DESTROY WIN` _%id%_ + + The core has instructed Monkey to destroy the named window. + +* `WINDOW TITLE WIN` _%id%_ `STR` _%str%_ + + The core supplied a titlebar title for the given window. + +* `WINDOW REDRAW WIN` _%id%_ + + The core asked that Monkey redraw the given window. + +* `WINDOW GET_DIMENSIONS WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_ + + The core asked Monkey what the dimensions of the window are. + Monkey has to respond immediately and returned the supplied width + and height values to the core. + +* `WINDOW NEW_CONTENT WIN` _%id%_ + + The core has informed Monkey that the named window has a new + content object. + +* `WINDOW NEW_ICON WIN` _%id%_ + + The core has informed Monkey that the named window has a new + icon (favicon) available. + +* `WINDOW START_THROBBER WIN` _%id%_ + + The core asked Monkey to start the throbber for the named + window. This indicates to the user that the window is busy. + +* `WINDOW STOP_THROBBER WIN` _%id%_ + + The core asked Monkey to stop the throbber for the named + window. This indicates to the user that the window is finished. + +* `WINDOW SET_SCROLL WIN` _%id%_ `X` _%n%_ `Y` _%n%_ + + The core asked Monkey to set the named window's scroll offsets + to the given X and Y position. + +* `WINDOW UPDATE_BOX WIN` _%id%_ `X` _%n%_ `Y` _%n%_ `WIDTH` _%n%_ `HEIGHT` _%n%_ + + The core asked Monkey to redraw the given portion of the content + display. Note these coordinates refer to the content, not the + viewport which Monkey is simulating. + +* `WINDOW UPDATE_EXTENT WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_ + + The core has told us that the content in the given window has a + total width and height as shown. This allows us (along with the + window's width and height) to know the scroll limits. + +* `WINDOW SET_STATUS WIN` _%id%_ `STR` _%str%_ + + The core has told us that the given window needs its status bar + updating with the given message. + +* `WINDOW SET_POINTER WIN` _%id%_ `POINTER` _%id%_ + + The core has told us to update the mouse pointer for the given + window to the given pointer ID. + +* `WINDOW SET_SCALE WIN` _%id%_ `SCALE` _%n%_ + + The core has asked us to scale the given window by the given scale + factor. + +* `WINDOW SET_URL WIN` _%id%_ `URL` _%url%_ + + The core has informed us that the given window's URL bar needs + updating to the given url. + +* `WINDOW GET_SCROLL WIN` _%id%_ `X` _%n%_ `Y` _%n%_ + + The core asked Monkey for the scroll offsets. Monkey returned the + numbers shown for the window named. + +* `WINDOW SCROLL_START WIN` _%id%_ + + The core asked Monkey to scroll the named window to the top/left. + +* `WINDOW POSITION_FRAME WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to position the named window as a frame at + the given coordinates of its parent. + +* `WINDOW SCROLL_VISIBLE WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to scroll the named window until the + indicated box is visible. + +* `WINDOW PLACE_CARET WIN` _%id%_ `X` _%n%_ `Y` _%n%_ `HEIGHT` _%n%_ + + The core asked Monkey to render a caret in the named window at the + indicated position with the indicated height. + +* `WINDOW REMOVE_CARET WIN` _%id%_ + + The core asked Monkey to remove any caret in the named window. + +* `WINDOW SCROLL_START WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to scroll the named window to the start of + the given box. + +* `WINDOW SELECT_MENU WIN` _%id%_ + + The core asked Monkey to produce a selection menu for the named + window. + +* `WINDOW SAVE_LINK WIN` _%id%_ `URL` _%url%_ `TITLE` _%str%_ + + The core asked Monkey to save a link from the given window with + the given URL and anchor title. + +* `WINDOW THUMBNAIL WIN` _%id%_ `URL` _%url%_ + + The core asked Monkey to render a thumbnail for the given window + which is currently at the given URL. + +* `WINDOW REDRAW WIN` _%id%_ `START` + + and + + `WINDOW REDRAW WIN` _%id%_ `STOP` + + The core wraps redraws in these messages. Thus `PLOT` responses can + be allocated to the appropriate window. + +### Download window messages + +* `DOWNLOAD_WINDOW CREATE DWIN` _%id%_ `WIN` _%id%_ + + The core asked Monkey to create a download window owned by the + given browser window. + +* `DOWNLOAD_WINDOW DATA DWIN` _%id%_ `SIZE` _%n%_ `DATA` _%str%_ + + The core asked Monkey to update the named download window with + the given byte size and data string. + +* `DOWNLOAD_WINDOW ERROR DWIN` _%id%_ `ERROR` _%str%_ + + The core asked Monkey to update the named download window with + the given error message. + +* `DOWNLOAD_WINDOW DONE DWIN` _%id%_ + + The core asked Monkey to destroy the named download window. + +### SSL Certificate messages + +* `SSLCERT VERIFY CERT` _%id%_ `URL` _%url%_ + + The core asked Monkey to say whether or not a given SSL + certificate is OK. + +> TODO: Implement the rest of the SSL certificat verification behaviour + +### 401 Login messages + +* `401LOGIN OPEN M4` _%id%_ `URL` _%url%_ `REALM` _%str%_ + + The core asked Monkey to ask for identification for the named + realm at the given URL. + +> TODO: Implement support to control the 401LOGIN process + +### Plotter messages + +> **Note, Monkey won't clip coordinates, but sometimes the core does.** + +* `PLOT CLIP X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to clip plotting to the given clipping + rectangle (X0,Y0) (X1,Y1) + +* `PLOT TEXT X` _%n%_ `Y` _%n%_ `STR` _%str%_ + + The core asked Monkey to plot the given string at the + given coordinates. + +* `PLOT LINE X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to plot a line with the given start + and end coordinates. + +* `PLOT RECT X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_ + + The core asked Monkey to plot a rectangle with the given + coordinates as the corners. + +* `PLOT BITMAP X` _%n%_ `Y` _%n%_ `WIDTH` _%n%_ `HEIGHT` _%n%_ + + The core asked Monkey to plot a bitmap at the given + coordinates, scaled to the given width/height. + +> TODO: Check if other things are implemented and add them to the docs diff --git a/frontends/amiga/corewindow.c b/frontends/amiga/corewindow.c index 6b2d9e8c6..1a94dd3b2 100644 --- a/frontends/amiga/corewindow.c +++ b/frontends/amiga/corewindow.c @@ -806,7 +806,7 @@ static const struct ami_win_event_table ami_cw_table = { * invalidated. * * \param[in] cw The core window to invalidate. - * \param[in] rect area to redraw or NULL for the entire window area. + * \param[in] r area to redraw or NULL for the entire window area. * \return NSERROR_OK on success or appropriate error code. */ static nserror @@ -920,6 +920,7 @@ nserror ami_corewindow_init(struct ami_corewindow *ami_cw) { /* setup the core window callback table */ ami_cw->cb_table = &ami_cw_cb_table; + ami_cw->drag_status = CORE_WINDOW_DRAG_NONE; /* clear some vars */ ami_cw->mouse_state = BROWSER_MOUSE_HOVER; diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c index 7eacda784..5c6700a68 100644 --- a/frontends/amiga/gui.c +++ b/frontends/amiga/gui.c @@ -90,6 +90,7 @@ #include <math.h> #include <string.h> #include <stdlib.h> +#include <limits.h> /* NetSurf core includes */ #include "utils/log.h" @@ -115,7 +116,6 @@ #include "desktop/hotlist.h" #include "desktop/version.h" #include "desktop/save_complete.h" -#include "desktop/scrollbar.h" #include "desktop/searchweb.h" /* NetSurf Amiga platform includes */ @@ -158,6 +158,11 @@ #define NSA_KBD_SCROLL_PX 10 #define NSA_MAX_HOTLIST_BUTTON_LEN 20 +#define SCROLL_TOP INT_MIN +#define SCROLL_PAGE_UP (INT_MIN + 1) +#define SCROLL_PAGE_DOWN (INT_MAX - 1) +#define SCROLL_BOTTOM (INT_MAX) + /* Extra mouse button defines to match those in intuition/intuition.h */ #define SIDEDOWN (IECODE_4TH_BUTTON) #define SIDEUP (IECODE_4TH_BUTTON | IECODE_UP_PREFIX) @@ -4596,7 +4601,7 @@ static void gui_window_destroy(struct gui_window *g) if(g->hw) { - ami_history_close(g->hw); + ami_history_local_destroy(g->hw); win_destroyed = true; } @@ -4986,7 +4991,7 @@ static bool gui_window_get_scroll(struct gui_window *g, int *restrict sx, int *r * content is shown. The amiga implementation scrolls the contents so * the specified point in the content is at the top of the viewport. * - * \param gw gui_window to scroll + * \param g gui_window to scroll * \param rect The rectangle to ensure is shown. * \return NSERROR_OK on success or apropriate error code. */ diff --git a/frontends/amiga/gui.h b/frontends/amiga/gui.h index 5cec82d84..bf4ec9139 100644 --- a/frontends/amiga/gui.h +++ b/frontends/amiga/gui.h @@ -87,7 +87,8 @@ enum }; struct find_window; -struct history_window; +struct ami_history_local_window; +struct ami_menu_data; #define AMI_GUI_TOOLBAR_MAX 20 @@ -110,8 +111,6 @@ struct ami_generic_window { const struct ami_win_event_table *tbl; }; -struct ami_menu_data; - struct gui_window_2 { struct ami_generic_window w; struct Window *win; @@ -174,7 +173,7 @@ struct gui_window int c_h_temp; int scrollx; int scrolly; - struct history_window *hw; + struct ami_history_local_window *hw; struct List dllist; struct hlcache_handle *favicon; bool throbbing; diff --git a/frontends/amiga/gui_menu.c b/frontends/amiga/gui_menu.c index 0469dd59b..6ee0800f8 100644 --- a/frontends/amiga/gui_menu.c +++ b/frontends/amiga/gui_menu.c @@ -326,7 +326,7 @@ HOOKF(void, ami_menu_item_browser_localhistory, APTR, window, struct IntuiMessag struct gui_window_2 *gwin; GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin); - ami_history_open(gwin->gw); + ami_history_local_present(gwin->gw); } HOOKF(void, ami_menu_item_browser_globalhistory, APTR, window, struct IntuiMessage *) diff --git a/frontends/amiga/history_local.c b/frontends/amiga/history_local.c index 368557dd6..c293f5909 100755..100644 --- a/frontends/amiga/history_local.c +++ b/frontends/amiga/history_local.c @@ -1,5 +1,5 @@ /* - * Copyright 2009, 2010 Chris Young <chris@unsatisfactorysoftware.co.uk> + * Copyright 2017 Chris Young <chris@unsatisfactorysoftware.co.uk> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,341 +16,300 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Browser history window (AmigaOS implementation). - * - * There is only one history window, not one per browser window. +/** + * \file + * Implementation of Amiga local history using core windows. */ -#include "amiga/os3support.h" - -#include <stdbool.h> +#include <stdint.h> #include <stdlib.h> -#include <string.h> + #include <proto/intuition.h> -#include <proto/exec.h> -#include <proto/graphics.h> -#include <intuition/icclass.h> -#include <proto/utility.h> -#include <proto/window.h> -#include <proto/space.h> -#include <proto/layout.h> + #include <classes/window.h> -#include <gadgets/space.h> +#include <gadgets/button.h> +#include <gadgets/layout.h> #include <gadgets/scroller.h> -#include <reaction/reaction.h> +#include <gadgets/space.h> +#include <images/label.h> + +#include <intuition/icclass.h> #include <reaction/reaction_macros.h> #include "utils/log.h" -#include "utils/utils.h" -#include "utils/messages.h" -#include "desktop/browser_history.h" -#include "netsurf/browser_window.h" +#include "netsurf/keypress.h" #include "netsurf/plotters.h" -#include "netsurf/window.h" -#include "graphics/rpattr.h" +#include "desktop/local_history.h" +#include "utils/messages.h" +#include "utils/nsoption.h" +#include "utils/nsurl.h" -#include "amiga/libs.h" -#include "amiga/misc.h" -#include "amiga/object.h" -#include "amiga/plotters.h" +#include "amiga/corewindow.h" #include "amiga/gui.h" +#include "amiga/libs.h" #include "amiga/history_local.h" +#include "amiga/utf8.h" -struct history_window { - struct ami_generic_window w; - struct Window *win; - Object *objects[GID_LAST]; - struct gui_window *gw; - struct Hook scrollerhook; - struct gui_globals *gg; -}; -static void ami_history_update_extent(struct history_window *hw); -HOOKF(void, ami_history_scroller_hook, Object *, object, struct IntuiMessage *); +/** + * Amiga local history viewing window context + */ +struct ami_history_local_window { + /** Amiga core window context */ + struct ami_corewindow core; -static BOOL ami_history_event(void *w); + /** Amiga GUI stuff */ + struct gui_window *gw; -static const struct ami_win_event_table ami_localhistory_table = { - ami_history_event, - NULL, /* we don't explicitly close the local history window on quit */ + /** local history viewer context data */ + struct local_history_session *session; }; +static struct ami_history_local_window *history_local_window = NULL; + /** - * Redraw history window. + * destroy a previously created local history view */ - -static void ami_history_redraw(struct history_window *hw) +nserror +ami_history_local_destroy(struct ami_history_local_window *history_local_win) { - struct IBox *bbox; - ULONG xs,ys; - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = &amiplot, - .priv = hw->gg - }; - - GetAttr(SCROLLER_Top,hw->objects[OID_HSCROLL],(ULONG *)&xs); - GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys); - if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) { - amiga_warn_user("NoMemory", ""); - return; - } + nserror res; -/* core should clear this area for us - SetRPAttrs(glob->rp, RPTAG_APenColor, 0xffffffff, TAG_DONE); - RectFill(glob->rp, 0, 0, bbox->Width - 1, bbox->Height - 1); -*/ + if (history_local_win == NULL) { + return NSERROR_OK; + } - browser_window_history_redraw_rectangle(hw->gw->bw, xs, ys, - bbox->Width + xs, bbox->Height + ys, 0, 0, &ctx); + res = local_history_fini(history_local_win->session); + if (res == NSERROR_OK) { + history_local_win->gw->hw = NULL; + res = ami_corewindow_fini(&history_local_win->core); /* closes the window for us */ + history_local_window = NULL; + } + return res; +} - ami_clearclipreg(hw->gg); - ami_history_update_extent(hw); +/** + * callback for mouse action for local history on core window + * + * \param ami_cw The Amiga core window structure. + * \param mouse_state netsurf mouse state on event + * \param x location of event + * \param y location of event + * \return NSERROR_OK on success otherwise apropriate error code + */ +static nserror +ami_history_local_mouse(struct ami_corewindow *ami_cw, + browser_mouse_state mouse_state, + int x, int y) +{ + struct ami_history_local_window *history_local_win; + /* technically degenerate container of */ + history_local_win = (struct ami_history_local_window *)ami_cw; + + nsurl *url; + + if(local_history_get_url(history_local_win->session, x, y, &url) == NSERROR_OK) { + if (url == NULL) { + SetGadgetAttrs( + (struct Gadget *)ami_cw->objects[GID_CW_DRAW], + ami_cw->win, + NULL, + GA_HintInfo, + NULL, + TAG_DONE); + } else { + SetGadgetAttrs( + (struct Gadget *)ami_cw->objects[GID_CW_DRAW], + ami_cw->win, + NULL, + GA_HintInfo, + nsurl_access(url), + TAG_DONE); + nsurl_unref(url); + } + } - BltBitMapRastPort(ami_plot_ra_get_bitmap(hw->gg), 0, 0, hw->win->RPort, - bbox->Left, bbox->Top, bbox->Width, bbox->Height, 0x0C0); + local_history_mouse_action(history_local_win->session, mouse_state, x, y); - ami_gui_free_space_box(bbox); + return NSERROR_OK; } - -/* exported interface documented in amiga/history_local.h */ -void ami_history_open(struct gui_window *gw) +/** + * callback for keypress for local history on core window + * + * \param ami_cw The Amiga core window structure. + * \param nskey The netsurf key code + * \return NSERROR_OK on success otherwise apropriate error code + */ +static nserror +ami_history_local_key(struct ami_corewindow *ami_cw, uint32_t nskey) { - struct history *history; - int width, height; + struct ami_history_local_window *history_local_win; - if (gw->bw == NULL) - return; - - history = browser_window_get_history(gw->bw); - if (history == NULL) - return; - - if(!gw->hw) - { - gw->hw = calloc(1, sizeof(struct history_window)); - gw->hw->gg = ami_plot_ra_alloc(scrn->Width, scrn->Height, false, true); - - gw->hw->gw = gw; - browser_window_history_size(gw->bw, &width, &height); - - gw->hw->scrollerhook.h_Entry = (void *)ami_history_scroller_hook; - gw->hw->scrollerhook.h_Data = gw->hw; - - gw->hw->objects[OID_MAIN] = WindowObj, - WA_ScreenTitle, ami_gui_get_screen_title(), - WA_Title, messages_get("History"), - WA_Activate, TRUE, - WA_DepthGadget, TRUE, - WA_DragBar, TRUE, - WA_CloseGadget, TRUE, - WA_SizeGadget, TRUE, - WA_PubScreen,scrn, - WA_InnerWidth,width, - WA_InnerHeight,height + 10, - WINDOW_SharedPort,sport, - WINDOW_UserData,gw->hw, - WINDOW_IconifyGadget, FALSE, - WINDOW_GadgetHelp, TRUE, - WINDOW_Position, WPOS_CENTERSCREEN, - WINDOW_HorizProp,1, - WINDOW_VertProp,1, - WINDOW_IDCMPHook,&gw->hw->scrollerhook, - WINDOW_IDCMPHookBits,IDCMP_IDCMPUPDATE, -// WA_ReportMouse,TRUE, - WA_IDCMP,IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE, // | IDCMP_MOUSEMOVE, - WINDOW_ParentGroup, gw->hw->objects[GID_MAIN] = LayoutVObj, - LAYOUT_AddChild, gw->hw->objects[GID_BROWSER] = SpaceObj, - GA_ID,GID_BROWSER, -// SPACE_MinWidth,width, -// SPACE_MinHeight,height, - SpaceEnd, - EndGroup, - EndWindow; - - gw->hw->win = (struct Window *)RA_OpenWindow(gw->hw->objects[OID_MAIN]); - ami_gui_win_list_add(gw->hw, AMINS_HISTORYWINDOW, &ami_localhistory_table); - - GetAttr(WINDOW_HorizObject,gw->hw->objects[OID_MAIN],(ULONG *)&gw->hw->objects[OID_HSCROLL]); - GetAttr(WINDOW_VertObject,gw->hw->objects[OID_MAIN],(ULONG *)&gw->hw->objects[OID_VSCROLL]); - - RefreshSetGadgetAttrs((APTR)gw->hw->objects[OID_VSCROLL],gw->hw->win,NULL, - GA_ID,OID_VSCROLL, - SCROLLER_Top,0, - ICA_TARGET,ICTARGET_IDCMP, - TAG_DONE); - - RefreshSetGadgetAttrs((APTR)gw->hw->objects[OID_HSCROLL],gw->hw->win,NULL, - GA_ID,OID_HSCROLL, - SCROLLER_Top,0, - ICA_TARGET,ICTARGET_IDCMP, - TAG_DONE); - } + /* technically degenerate container of */ + history_local_win = (struct ami_history_local_window *)ami_cw; - ami_history_redraw(gw->hw); + if (local_history_keypress(history_local_win->session, nskey)) { + return NSERROR_OK; + } + return NSERROR_NOT_IMPLEMENTED; } - /** - * Handle mouse clicks in the history window. + * callback on draw event for certificate verify on core window * - * \return true if the event was handled, false to pass it on + * \param ami_cw The Amiga core window structure. + * \param x the x coordinate to draw + * \param y the y coordinate to draw + * \param r The rectangle of the window that needs updating. + * \param ctx The drawing context + * \return NSERROR_OK on success otherwise apropriate error code */ +static nserror +ami_history_local_draw(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx) +{ + struct ami_history_local_window *history_local_win; -static bool ami_history_click(struct history_window *hw, uint16 code) + /* technically degenerate container of */ + history_local_win = (struct ami_history_local_window *)ami_cw; + + //ctx->plot->clip(ctx, r); //?? + local_history_redraw(history_local_win->session, x, y, r, ctx); + + return NSERROR_OK; +} + +static nserror +ami_history_local_create_window(struct ami_history_local_window *history_local_win) { - int x, y; - struct IBox *bbox; - ULONG xs, ys; + struct ami_corewindow *ami_cw = (struct ami_corewindow *)&history_local_win->core; + ULONG refresh_mode = WA_SmartRefresh; - if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) { - amiga_warn_user("NoMemory", ""); - return false; + if(nsoption_bool(window_simple_refresh) == true) { + refresh_mode = WA_SimpleRefresh; } - GetAttr(SCROLLER_Top,hw->objects[OID_HSCROLL],(ULONG *)&xs); - x = hw->win->MouseX - bbox->Left +xs; - GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys); - y = hw->win->MouseY - bbox->Top + ys; - - ami_gui_free_space_box(bbox); - - switch(code) - { - case SELECTUP: - browser_window_history_click(hw->gw->bw, x, y, false); - ami_history_redraw(hw); - ami_schedule_redraw(hw->gw->shared, true); - break; - - case MIDDLEUP: - browser_window_history_click(hw->gw->bw, x, y, true); - ami_history_redraw(hw); - break; + ami_cw->objects[GID_CW_WIN] = WindowObj, + WA_ScreenTitle, ami_gui_get_screen_title(), + WA_Title, ami_cw->wintitle, + WA_Activate, TRUE, + WA_DepthGadget, TRUE, + WA_DragBar, TRUE, + WA_CloseGadget, TRUE, + WA_SizeGadget, TRUE, + WA_SizeBRight, TRUE, + WA_Width, 100, + WA_Height, 100, + WA_PubScreen, scrn, + WA_ReportMouse, TRUE, + refresh_mode, TRUE, + WA_IDCMP, IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE | + IDCMP_RAWKEY | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE | + IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW, + WINDOW_IDCMPHook, &ami_cw->idcmp_hook, + WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE | + IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW, + WINDOW_SharedPort, sport, + WINDOW_HorizProp, 1, + WINDOW_VertProp, 1, + WINDOW_UserData, history_local_win, +// WINDOW_MenuStrip, NULL, + WINDOW_MenuUserData, WGUD_HOOK, + WINDOW_IconifyGadget, FALSE, + WINDOW_Position, WPOS_CENTERSCREEN, + WINDOW_ParentGroup, ami_cw->objects[GID_CW_MAIN] = LayoutVObj, + LAYOUT_AddChild, ami_cw->objects[GID_CW_DRAW] = SpaceObj, + GA_ID, GID_CW_DRAW, + SPACE_Transparent, TRUE, + SPACE_BevelStyle, BVS_DISPLAY, + GA_RelVerify, TRUE, + SpaceEnd, + EndGroup, + EndWindow; + + if(ami_cw->objects[GID_CW_WIN] == NULL) { + return NSERROR_NOMEM; } - return true; + return NSERROR_OK; } -void ami_history_close(struct history_window *hw) +/* exported interface documented in amiga/history_local.h */ +nserror ami_history_local_present(struct gui_window *gw) { - ami_plot_ra_free(hw->gg); - hw->gw->hw = NULL; - DisposeObject(hw->objects[OID_MAIN]); - ami_gui_win_list_remove(hw); -} + struct ami_history_local_window *ncwin; + nserror res; + int width, height; -static BOOL ami_history_event(void *w) -{ - /* return TRUE if window destroyed */ - struct history_window *hw = (struct history_window *)w; - ULONG result = 0; - uint16 code; - const char *url; - struct IBox *bbox; - ULONG xs, ys; - - while((result = RA_HandleInput(hw->objects[OID_MAIN],&code)) != WMHI_LASTMSG) - { - switch(result & WMHI_CLASSMASK) // class - { -/* no menus yet, copied in as will probably need it later - case WMHI_MENUPICK: - item = ItemAddress(gwin->win->MenuStrip,code); - while (code != MENUNULL) - { - ami_menupick(code,gwin); - if(win_destroyed) break; - code = item->NextSelect; - } - break; -*/ - - case WMHI_MOUSEMOVE: - GetAttr(SCROLLER_Top, hw->objects[OID_HSCROLL], (ULONG *)&xs); - GetAttr(SCROLLER_Top, hw->objects[OID_VSCROLL], (ULONG *)&ys); - - if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) { - amiga_warn_user("NoMemory", ""); - break; - } - - url = browser_window_history_position_url(hw->gw->bw, - hw->win->MouseX - bbox->Left + xs, - hw->win->MouseY - bbox->Top + ys); - - ami_gui_free_space_box(bbox); - - RefreshSetGadgetAttrs((APTR)hw->objects[GID_BROWSER], - hw->win, NULL, - GA_HintInfo, url, - TAG_DONE); - break; - - case WMHI_NEWSIZE: - ami_history_redraw(hw); - break; - - case WMHI_MOUSEBUTTONS: - ami_history_click(hw,code); - break; - - case WMHI_CLOSEWINDOW: - ami_history_close(hw); - return TRUE; - break; + if(history_local_window != NULL) { + //windowtofront() + + if (gw->hw != NULL) { + res = local_history_set(gw->hw->session, gw->bw); + return res; } + + return NSERROR_OK; } - return FALSE; -} -static void ami_history_update_extent(struct history_window *hw) -{ - struct IBox *bbox; - int width, height; + ncwin = calloc(1, sizeof(struct ami_history_local_window)); + if (ncwin == NULL) { + return NSERROR_NOMEM; + } - browser_window_history_size(hw->gw->bw, &width, &height); - if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) { - amiga_warn_user("NoMemory", ""); - return; + ncwin->core.wintitle = ami_utf8_easy((char *)messages_get("History")); + + res = ami_history_local_create_window(ncwin); + if (res != NSERROR_OK) { + LOG("SSL UI builder init failed"); + ami_utf8_free(ncwin->core.wintitle); + free(ncwin); + return res; } - RefreshSetGadgetAttrs((APTR)hw->objects[OID_VSCROLL], hw->win, NULL, - GA_ID, OID_VSCROLL, - SCROLLER_Total, height, - SCROLLER_Visible, bbox->Height, - ICA_TARGET, ICTARGET_IDCMP, - TAG_DONE); + /* initialise Amiga core window */ + ncwin->core.draw = ami_history_local_draw; + ncwin->core.key = ami_history_local_key; + ncwin->core.mouse = ami_history_local_mouse; + ncwin->core.close = ami_history_local_destroy; + ncwin->core.event = NULL; + ncwin->core.drag_end = NULL; + ncwin->core.icon_drop = NULL; + + res = ami_corewindow_init(&ncwin->core); + if (res != NSERROR_OK) { + ami_utf8_free(ncwin->core.wintitle); + DisposeObject(ncwin->core.objects[GID_CW_WIN]); + free(ncwin); + return res; + } + + res = local_history_init(ncwin->core.cb_table, + (struct core_window *)ncwin, + gw->bw, + &ncwin->session); + if (res != NSERROR_OK) { + ami_utf8_free(ncwin->core.wintitle); + DisposeObject(ncwin->core.objects[GID_CW_WIN]); + free(ncwin); + return res; + } + + res = local_history_get_size(ncwin->session, + &width, + &height); - RefreshSetGadgetAttrs((APTR)hw->objects[OID_HSCROLL], hw->win, NULL, - GA_ID, OID_HSCROLL, - SCROLLER_Total, width, - SCROLLER_Visible, bbox->Width, - ICA_TARGET, ICTARGET_IDCMP, + /*TODO: Adjust these to account for window borders */ + + SetAttrs(ncwin->core.objects[GID_CW_WIN], + WA_Width, width, + WA_Height, height, TAG_DONE); - ami_gui_free_space_box(bbox); + ncwin->gw = gw; + history_local_window = ncwin; + gw->hw = ncwin; + + return NSERROR_OK; } -HOOKF(void, ami_history_scroller_hook, Object *, object, struct IntuiMessage *) -{ - ULONG gid; - struct history_window *hw = hook->h_Data; - - if (msg->Class == IDCMP_IDCMPUPDATE) - { - gid = GetTagData( GA_ID, 0, msg->IAddress ); - - switch( gid ) - { - case OID_HSCROLL: - case OID_VSCROLL: - ami_history_redraw(hw); - break; - } - } -// ReplyMsg((struct Message *)msg); -} diff --git a/frontends/amiga/history_local.h b/frontends/amiga/history_local.h index 97aea0579..72ba7fa8b 100755..100644 --- a/frontends/amiga/history_local.h +++ b/frontends/amiga/history_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Chris Young <chris@unsatisfactorysoftware.co.uk> + * Copyright 2017 Chris Young <chris@unsatisfactorysoftware.co.uk> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,23 +16,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef AMIGA_HISTORY_LOCAL_H -#define AMIGA_HISTORY_LOCAL_H - -#include <exec/types.h> -#include <intuition/classusr.h> +#ifndef AMIGA_HISTORY_GLOBAL_H +#define AMIGA_HISTORY_GLOBAL_H struct gui_window; -struct gui_globals; -struct history_window; - -/** - * Open history window. - * - * \param gw gui_window to open history for - */ -void ami_history_open(struct gui_window *gw); +struct ami_history_local_window; -void ami_history_close(struct history_window *hw); +/** Open the global history viewer */ +nserror ami_history_local_present(struct gui_window *gw); +nserror ami_history_local_destroy(struct ami_history_local_window *history_local_win); #endif diff --git a/frontends/amiga/os3support.c b/frontends/amiga/os3support.c index 5c1e40d1e..6dc95795f 100644 --- a/frontends/amiga/os3support.c +++ b/frontends/amiga/os3support.c @@ -338,7 +338,7 @@ int64 GetFileSize(BPTR fh) ExamineFH(fh, fib); size = fib->fib_Size; - free(fib); + FreeDosObject(DOS_FIB, fib); return (int64)size; } diff --git a/frontends/framebuffer/Makefile b/frontends/framebuffer/Makefile index 6d2acb079..760e85b25 100644 --- a/frontends/framebuffer/Makefile +++ b/frontends/framebuffer/Makefile @@ -146,7 +146,7 @@ $(eval $(foreach V,$(filter FB_FONT_$(NETSURF_FB_FONTLIB)_%,$(.VARIABLES)),$(cal # S_FRONTEND are sources purely for the framebuffer build S_FRONTEND := gui.c framebuffer.c schedule.c bitmap.c fetch.c \ - findfile.c localhistory.c clipboard.c + findfile.c corewindow.c local_history.c clipboard.c # toolkit sources S_FRAMEBUFFER_FBTK := fbtk.c event.c fill.c bitmap.c user.c window.c \ diff --git a/frontends/framebuffer/corewindow.c b/frontends/framebuffer/corewindow.c new file mode 100644 index 000000000..93f88ff61 --- /dev/null +++ b/frontends/framebuffer/corewindow.c @@ -0,0 +1,262 @@ +/* + * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * framebuffer generic core window interface. + * + * Provides interface for core renderers to the framebufefr toolkit + * drawable area. + * + * This module is an object that must be encapsulated. Client users + * should embed a struct fb_corewindow at the beginning of their + * context for this display surface, fill in relevant data and then + * call fb_corewindow_init() + * + * The fb core window structure requires the callback for draw, key and + * mouse operations. + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <limits.h> + +#include <libnsfb.h> +#include <libnsfb_plot.h> +#include <libnsfb_event.h> + +#include "utils/log.h" +#include "utils/utils.h" +#include "utils/messages.h" +#include "utils/utf8.h" +#include "utils/nsoption.h" +#include "netsurf/keypress.h" +#include "netsurf/mouse.h" +#include "netsurf/plot_style.h" + +#include "framebuffer/gui.h" +#include "framebuffer/fbtk.h" +#include "framebuffer/corewindow.h" + + +/* toolkit event handlers that do generic things and call internal callbacks */ + + +static int +fb_cw_mouse_press_event(fbtk_widget_t *widget, fbtk_callback_info *cbi) +{ + struct fb_corewindow *fb_cw = (struct fb_corewindow *)cbi->context; + browser_mouse_state state; + + /** \todo frambuffer corewindow mouse event handling needs improving */ + if (cbi->event->type != NSFB_EVENT_KEY_UP) { + state = BROWSER_MOUSE_HOVER; + } else { + state = BROWSER_MOUSE_PRESS_1; + } + + fb_cw->mouse(fb_cw, state, cbi->x, cbi->y); + + return 1; +} + +/* +static bool +fb_cw_input_event(toolkit_widget *widget, void *ctx) +{ + struct fb_corewindow *fb_cw = (struct fb_corewindow *)ctx; + + fb_cw->key(fb_cw, keycode); + + return true; +} +*/ + +/** + * handler for toolkit window redraw event + */ +static int fb_cw_draw_event(fbtk_widget_t *widget, fbtk_callback_info *cbi) +{ + struct fb_corewindow *fb_cw; + nsfb_bbox_t rbox; + struct rect clip; + + fb_cw = (struct fb_corewindow *)cbi->context; + + rbox.x0 = fbtk_get_absx(widget); + rbox.y0 = fbtk_get_absy(widget); + + rbox.x1 = rbox.x0 + fbtk_get_width(widget); + rbox.y1 = rbox.y0 + fbtk_get_height(widget); + + nsfb_claim(fbtk_get_nsfb(widget), &rbox); + + clip.x0 = fb_cw->scrollx; + clip.y0 = fb_cw->scrolly; + clip.x1 = fbtk_get_width(widget) + fb_cw->scrollx; + clip.y1 = fbtk_get_height(widget) + fb_cw->scrolly; + + fb_cw->draw(fb_cw, &clip); + + nsfb_update(fbtk_get_nsfb(widget), &rbox); + + return 0; +} + + +/** + * callback from core to request a redraw + */ +static nserror +fb_cw_invalidate(struct core_window *cw, const struct rect *r) +{ +/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw; + + toolkit_widget_queue_draw_area(fb_cw->widget, + r->x0, r->y0, + r->x1 - r->x0, r->y1 - r->y0); +*/ + return NSERROR_OK; +} + + +static void +fb_cw_update_size(struct core_window *cw, int width, int height) +{ +/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw; + + toolkit_widget_set_size_request(FB_WIDGET(fb_cw->drawing_area), + width, height); +*/ +} + + +static void +fb_cw_scroll_visible(struct core_window *cw, const struct rect *r) +{ +/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw; + + toolkit_scroll_widget(fb_cw->widget, r); +*/ +} + + +static void +fb_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) +{ + struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw; + + *width = fbtk_get_width(fb_cw->drawable); + *height = fbtk_get_height(fb_cw->drawable); +} + + +static void +fb_cw_drag_status(struct core_window *cw, core_window_drag_status ds) +{ + struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw; + fb_cw->drag_status = ds; +} + + +struct core_window_callback_table fb_cw_cb_table = { + .invalidate = fb_cw_invalidate, + .update_size = fb_cw_update_size, + .scroll_visible = fb_cw_scroll_visible, + .get_window_dimensions = fb_cw_get_window_dimensions, + .drag_status = fb_cw_drag_status +}; + +/* exported function documented fb/corewindow.h */ +nserror fb_corewindow_init(fbtk_widget_t *parent, struct fb_corewindow *fb_cw) +{ + int furniture_width; + + furniture_width = nsoption_int(fb_furniture_size); + + /* setup the core window callback table */ + fb_cw->cb_table = &fb_cw_cb_table; + fb_cw->drag_status = CORE_WINDOW_DRAG_NONE; + + /* container window */ + fb_cw->wnd = fbtk_create_window(parent, 0, 0, 0, 0, 0); + + fb_cw->drawable = fbtk_create_user(fb_cw->wnd, + 0, 0, + -furniture_width, -furniture_width, + fb_cw); + + fbtk_set_handler(fb_cw->drawable, + FBTK_CBT_REDRAW, + fb_cw_draw_event, + fb_cw); + + fbtk_set_handler(fb_cw->drawable, + FBTK_CBT_CLICK, + fb_cw_mouse_press_event, + fb_cw); +/* + fbtk_set_handler(fb_cw->drawable, + FBTK_CBT_INPUT, + fb_cw_input_event, + fb_cw); + + fbtk_set_handler(fb_cw->drawable, + FBTK_CBT_POINTERMOVE, + fb_cw_move_event, + fb_cw); +*/ + + /* create horizontal scrollbar */ + fb_cw->hscroll = fbtk_create_hscroll(fb_cw->wnd, + 0, + fbtk_get_height(fb_cw->wnd) - furniture_width, + fbtk_get_width(fb_cw->wnd) - furniture_width, + furniture_width, + FB_SCROLL_COLOUR, + FB_FRAME_COLOUR, + NULL, + NULL); + + fb_cw->vscroll = fbtk_create_vscroll(fb_cw->wnd, + fbtk_get_width(fb_cw->wnd) - furniture_width, + 0, + furniture_width, + fbtk_get_height(fb_cw->wnd) - furniture_width, + FB_SCROLL_COLOUR, + FB_FRAME_COLOUR, + NULL, + NULL); + + fbtk_create_fill(fb_cw->wnd, + fbtk_get_width(fb_cw->wnd) - furniture_width, + fbtk_get_height(fb_cw->wnd) - furniture_width, + furniture_width, + furniture_width, + FB_FRAME_COLOUR); + + + return NSERROR_OK; +} + +/* exported interface documented in fb/corewindow.h */ +nserror fb_corewindow_fini(struct fb_corewindow *fb_cw) +{ + return NSERROR_OK; +} diff --git a/frontends/framebuffer/corewindow.h b/frontends/framebuffer/corewindow.h new file mode 100644 index 000000000..5546c09b6 --- /dev/null +++ b/frontends/framebuffer/corewindow.h @@ -0,0 +1,107 @@ +/* + * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef FB_COREWINDOW_H +#define FB_COREWINDOW_H + +#include "netsurf/core_window.h" + +/** + * fb core window state + */ +struct fb_corewindow { + + /** + * framebuffer toolkit window. + */ + struct fbtk_widget_s *wnd; + /** + * framebuffer toolkit horizontal scrollbar. + */ + struct fbtk_widget_s *hscroll; + /** + * framebuffer toolkit vertical scrollbar. + */ + struct fbtk_widget_s *vscroll; + /** + * framebuffer toolkit user drawable widget. + */ + struct fbtk_widget_s *drawable; + + int scrollx, scrolly; /**< scroll offsets. */ + + + /** drag status set by core */ + core_window_drag_status drag_status; + + /** table of callbacks for core window operations */ + struct core_window_callback_table *cb_table; + + /** + * callback to draw on drawable area of fb core window + * + * \param fb_cw The fb core window structure. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise apropriate error code + */ + nserror (*draw)(struct fb_corewindow *fb_cw, struct rect *r); + + /** + * callback for keypress on fb core window + * + * \param fb_cw The fb core window structure. + * \param nskey The netsurf key code. + * \return NSERROR_OK if key processed, + * NSERROR_NOT_IMPLEMENTED if key not processed + * otherwise apropriate error code + */ + nserror (*key)(struct fb_corewindow *fb_cw, uint32_t nskey); + + /** + * callback for mouse event on fb core window + * + * \param fb_cw The fb core window structure. + * \param mouse_state mouse state + * \param x location of event + * \param y location of event + * \return NSERROR_OK on sucess otherwise apropriate error code. + */ + nserror (*mouse)(struct fb_corewindow *fb_cw, browser_mouse_state mouse_state, int x, int y); +}; + + +/** + * initialise elements of fb core window. + * + * As a pre-requisite the draw, key and mouse callbacks must be defined + * + * \param fb_cw A fb core window structure to initialise + * \return NSERROR_OK on successful initialisation otherwise error code. + */ +nserror fb_corewindow_init(fbtk_widget_t *parent, struct fb_corewindow *fb_cw); + + +/** + * finalise elements of fb core window. + * + * \param fb_cw A fb core window structure to initialise + * \return NSERROR_OK on successful finalisation otherwise error code. + */ +nserror fb_corewindow_fini(struct fb_corewindow *fb_cw); + +#endif diff --git a/frontends/framebuffer/framebuffer.c b/frontends/framebuffer/framebuffer.c index 649862aa3..de8a3695d 100644 --- a/frontends/framebuffer/framebuffer.c +++ b/frontends/framebuffer/framebuffer.c @@ -333,7 +333,10 @@ framebuffer_plot_bitmap(const struct redraw_context *ctx, loc.x1 = loc.x0 + width; loc.y1 = loc.y0 + height; - return nsfb_plot_copy(bm, NULL, nsfb, &loc); + if (!nsfb_plot_copy(bm, NULL, nsfb, &loc)) { + return NSERROR_INVALID; + } + return NSERROR_OK; } nsfb_plot_get_clip(nsfb, &clipbox); diff --git a/frontends/framebuffer/gui.c b/frontends/framebuffer/gui.c index 062cb5659..1460c77f6 100644 --- a/frontends/framebuffer/gui.c +++ b/frontends/framebuffer/gui.c @@ -54,6 +54,7 @@ #include "framebuffer/clipboard.h" #include "framebuffer/fetch.h" #include "framebuffer/bitmap.h" +#include "framebuffer/local_history.h" #define NSFB_TOOLBAR_DEFAULT_LAYOUT "blfsrutc" @@ -1150,7 +1151,7 @@ fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi) if (cbi->event->type != NSFB_EVENT_KEY_UP) return 0; - fb_localhistory_map(gw->localhistory); + fb_local_history_present(fbtk, gw->bw); return 0; } @@ -1782,7 +1783,6 @@ gui_window_create(struct browser_window *bw, gw->bw = bw; create_normal_browser_window(gw, nsoption_int(fb_furniture_size)); - gw->localhistory = fb_create_localhistory(bw, fbtk, nsoption_int(fb_furniture_size)); /* map and request redraw of gui window */ fbtk_set_mapping(gw->window, true); diff --git a/frontends/framebuffer/gui.h b/frontends/framebuffer/gui.h index 0de1add69..abb27c4bb 100644 --- a/frontends/framebuffer/gui.h +++ b/frontends/framebuffer/gui.h @@ -27,17 +27,6 @@ typedef struct fb_cursor_s fb_cursor_t; /* bounding box */ typedef struct nsfb_bbox_s bbox_t; -struct gui_localhistory { - struct browser_window *bw; - - struct fbtk_widget_s *window; - struct fbtk_widget_s *hscroll; - struct fbtk_widget_s *vscroll; - struct fbtk_widget_s *history; - - int scrollx, scrolly; /**< scroll offsets. */ -}; - struct gui_window { struct browser_window *bw; @@ -59,8 +48,6 @@ struct gui_window { int throbber_index; - struct gui_localhistory *localhistory; - struct gui_window *next; struct gui_window *prev; }; @@ -68,13 +55,8 @@ struct gui_window { extern struct gui_window *window_list; -struct gui_localhistory *fb_create_localhistory(struct browser_window *bw, - struct fbtk_widget_s *parent, int furniture_width); -void fb_localhistory_map(struct gui_localhistory * glh); - void gui_resize(struct fbtk_widget_s *root, int width, int height); - #endif /* NETSURF_FB_GUI_H */ /* diff --git a/frontends/framebuffer/local_history.c b/frontends/framebuffer/local_history.c new file mode 100644 index 000000000..cc45b1f29 --- /dev/null +++ b/frontends/framebuffer/local_history.c @@ -0,0 +1,248 @@ +/* + * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Implementation of framebuffer local history manager. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <limits.h> + +#include <libnsfb.h> +#include <libnsfb_plot.h> +#include <libnsfb_event.h> + +#include "utils/log.h" +#include "netsurf/keypress.h" +#include "netsurf/plotters.h" +#include "desktop/local_history.h" + +#include "framebuffer/gui.h" +#include "framebuffer/fbtk.h" +#include "framebuffer/framebuffer.h" +#include "framebuffer/corewindow.h" +#include "framebuffer/local_history.h" + +struct fb_local_history_window { + struct fb_corewindow core; + + struct local_history_session *session; +}; + +static struct fb_local_history_window *local_history_window = NULL; + + +/** + * callback for mouse action on local history window + * + * \param fb_cw The fb core window structure. + * \param mouse_state netsurf mouse state on event + * \param x location of event + * \param y location of event + * \return NSERROR_OK on success otherwise apropriate error code + */ +static nserror +fb_local_history_mouse(struct fb_corewindow *fb_cw, + browser_mouse_state mouse_state, + int x, int y) +{ + struct fb_local_history_window *lhw; + /* technically degenerate container of */ + lhw = (struct fb_local_history_window *)fb_cw; + + local_history_mouse_action(lhw->session, mouse_state, x, y); + + if (mouse_state != BROWSER_MOUSE_HOVER) { + fbtk_set_mapping(lhw->core.wnd, false); + } + + return NSERROR_OK; +} + + +/** + * callback for keypress on local history window + * + * \param fb_cw The fb core window structure. + * \param nskey The netsurf key code + * \return NSERROR_OK on success otherwise apropriate error code + */ +static nserror +fb_local_history_key(struct fb_corewindow *fb_cw, uint32_t nskey) +{ + struct fb_local_history_window *lhw; + /* technically degenerate container of */ + lhw = (struct fb_local_history_window *)fb_cw; + + if (local_history_keypress(lhw->session, nskey)) { + return NSERROR_OK; + } + return NSERROR_NOT_IMPLEMENTED; +} + + +/** + * callback on draw event for local history window + * + * \param fb_cw The fb core window structure. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise apropriate error code + */ +static nserror +fb_local_history_draw(struct fb_corewindow *fb_cw, struct rect *r) +{ + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &fb_plotters + }; + struct fb_local_history_window *lhw; + + /* technically degenerate container of */ + lhw = (struct fb_local_history_window *)fb_cw; + + local_history_redraw(lhw->session, 0, 0, r, &ctx); + + return NSERROR_OK; +} + +/** + * Creates the window for the local history view. + * + * \return NSERROR_OK on success else appropriate error code on faliure. + */ +static nserror +fb_local_history_init(fbtk_widget_t *parent, + struct browser_window *bw, + struct fb_local_history_window **win_out) +{ + struct fb_local_history_window *ncwin; + nserror res; + + /* memoise window so it can be represented when necessary + * instead of recreating every time. + */ + if ((*win_out) != NULL) { + res = local_history_set((*win_out)->session, bw); + return res; + } + + ncwin = calloc(1, sizeof(*ncwin)); + if (ncwin == NULL) { + return NSERROR_NOMEM; + } + + ncwin->core.draw = fb_local_history_draw; + ncwin->core.key = fb_local_history_key; + ncwin->core.mouse = fb_local_history_mouse; + + res = fb_corewindow_init(parent, &ncwin->core); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + res = local_history_init(ncwin->core.cb_table, + (struct core_window *)ncwin, + bw, + &ncwin->session); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + *win_out = ncwin; + + return NSERROR_OK; +} + + +/* exported function documented gtk/history.h */ +nserror fb_local_history_present(fbtk_widget_t *parent, + struct browser_window *bw) +{ + nserror res; + int prnt_width, prnt_height; + int width, height; + + res = fb_local_history_init(parent, bw, &local_history_window); + if (res == NSERROR_OK) { + + prnt_width = fbtk_get_width(parent); + prnt_height = fbtk_get_height(parent); + + /* resize history widget ensureing the drawing area is + * no larger than parent window + */ + res = local_history_get_size(local_history_window->session, + &width, + &height); + if (width > prnt_width) { + width = prnt_width; + } + if (height > prnt_height) { + height = prnt_height; + } + /* should update scroll area with contents */ + + fbtk_set_zorder(local_history_window->core.wnd, INT_MIN); + fbtk_set_mapping(local_history_window->core.wnd, true); + } + + return res; +} + + +/* exported function documented gtk/history.h */ +nserror fb_local_history_hide(void) +{ + nserror res = NSERROR_OK; + + if (local_history_window != NULL) { + fbtk_set_mapping(local_history_window->core.wnd, false); + + res = local_history_set(local_history_window->session, NULL); + } + + return res; +} + + +/* exported function documented gtk/history.h */ +nserror fb_local_history_destroy(void) +{ + nserror res; + + if (local_history_window == NULL) { + return NSERROR_OK; + } + + res = local_history_fini(local_history_window->session); + if (res == NSERROR_OK) { + res = fb_corewindow_fini(&local_history_window->core); + //gtk_widget_destroy(GTK_WIDGET(local_history_window->wnd)); + free(local_history_window); + local_history_window = NULL; + } + + return res; + +} diff --git a/frontends/framebuffer/local_history.h b/frontends/framebuffer/local_history.h new file mode 100644 index 000000000..929eeacd8 --- /dev/null +++ b/frontends/framebuffer/local_history.h @@ -0,0 +1,49 @@ +/* + * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Interface to framebuffer local history manager + */ + +#ifndef FB_LOCAL_HISTORY_H +#define FB_LOCAL_HISTORY_H + +struct browser_window; + +/** + * make the local history window visible. + * + * \return NSERROR_OK on success else appropriate error code on faliure. + */ +nserror fb_local_history_present(fbtk_widget_t *parent, struct browser_window *bw); + +/** + * hide the local history window from being visible. + * + * \return NSERROR_OK on success else appropriate error code on faliure. + */ +nserror fb_local_history_hide(void); + +/** + * Destroys the local history window and performs any other necessary cleanup + * actions. + */ +nserror fb_local_history_destroy(void); + +#endif diff --git a/frontends/framebuffer/localhistory.c b/frontends/framebuffer/localhistory.c deleted file mode 100644 index 3192f0747..000000000 --- a/frontends/framebuffer/localhistory.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2010 Vincent Sanders <vince@simtec.co.uk> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdbool.h> -#include <stdlib.h> -#include <limits.h> - -#include <libnsfb.h> -#include <libnsfb_plot.h> -#include <libnsfb_event.h> - -#include "desktop/browser_history.h" -#include "netsurf/plotters.h" - -#include "framebuffer/gui.h" -#include "framebuffer/fbtk.h" -#include "framebuffer/framebuffer.h" - -static int -localhistory_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi) -{ - struct gui_localhistory *glh = cbi->context; - nsfb_bbox_t rbox; - - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = &fb_plotters - }; - - rbox.x0 = fbtk_get_absx(widget); - rbox.y0 = fbtk_get_absy(widget); - - rbox.x1 = rbox.x0 + fbtk_get_width(widget); - rbox.y1 = rbox.y0 + fbtk_get_height(widget); - - nsfb_claim(fbtk_get_nsfb(widget), &rbox); - - nsfb_plot_rectangle_fill(fbtk_get_nsfb(widget), &rbox, 0xffffffff); - - browser_window_history_redraw_rectangle(glh->bw, - glh->scrollx, - glh->scrolly, - fbtk_get_width(widget) + glh->scrollx, - fbtk_get_height(widget) + glh->scrolly, - 0, 0, &ctx); - - nsfb_update(fbtk_get_nsfb(widget), &rbox); - - return 0; -} - -static int -localhistory_click(fbtk_widget_t *widget, fbtk_callback_info *cbi) -{ - struct gui_localhistory *glh = cbi->context; - - if (cbi->event->type != NSFB_EVENT_KEY_UP) - return 0; - - browser_window_history_click(glh->bw, cbi->x, cbi->y, false); - - fbtk_set_mapping(glh->window, false); - - return 1; -} - -struct gui_localhistory * -fb_create_localhistory(struct browser_window *bw, - fbtk_widget_t *parent, - int furniture_width) -{ - struct gui_localhistory *glh; - glh = calloc(1, sizeof(struct gui_localhistory)); - - if (glh == NULL) - return NULL; - - glh->bw = bw; - - /* container window */ - glh->window = fbtk_create_window(parent, 0, 0, 0, 0, 0); - - glh->history = fbtk_create_user(glh->window, 0, 0, -furniture_width, -furniture_width, glh); - - fbtk_set_handler(glh->history, FBTK_CBT_REDRAW, localhistory_redraw, glh); - fbtk_set_handler(glh->history, FBTK_CBT_CLICK, localhistory_click, glh); - /* - fbtk_set_handler(gw->localhistory, FBTK_CBT_INPUT, fb_browser_window_input, gw); - fbtk_set_handler(gw->localhistory, FBTK_CBT_POINTERMOVE, fb_browser_window_move, bw); - */ - - /* create horizontal scrollbar */ - glh->hscroll = fbtk_create_hscroll(glh->window, - 0, - fbtk_get_height(glh->window) - furniture_width, - fbtk_get_width(glh->window) - furniture_width, - furniture_width, - FB_SCROLL_COLOUR, - FB_FRAME_COLOUR, - NULL, - NULL); - - glh->vscroll = fbtk_create_vscroll(glh->window, - fbtk_get_width(glh->window) - furniture_width, - 0, - furniture_width, - fbtk_get_height(glh->window) - furniture_width, - FB_SCROLL_COLOUR, - FB_FRAME_COLOUR, - NULL, - NULL); - - fbtk_create_fill(glh->window, - fbtk_get_width(glh->window) - furniture_width, - fbtk_get_height(glh->window) - furniture_width, - furniture_width, - furniture_width, - FB_FRAME_COLOUR); - - return glh; -} - -void -fb_localhistory_map(struct gui_localhistory * glh) -{ - fbtk_set_zorder(glh->window, INT_MIN); - fbtk_set_mapping(glh->window, true); -} diff --git a/frontends/gtk/bitmap.c b/frontends/gtk/bitmap.c index b42814295..36b614cf9 100644 --- a/frontends/gtk/bitmap.c +++ b/frontends/gtk/bitmap.c @@ -18,9 +18,9 @@ /** * \file - * Generic bitmap handling (GDK / GTK+ implementation). + * GTK bitmap handling. * - * This implements the interface given by desktop/bitmap.h using GdkPixbufs. + * This implements the bitmap interface using cairo image surfaces */ #include <assert.h> diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c index dc77e1c4e..500cd07f6 100644 --- a/frontends/gtk/cookies.c +++ b/frontends/gtk/cookies.c @@ -246,7 +246,7 @@ static nserror nsgtk_cookies_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsgtk_cookie_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c index 9ad644d7f..ddc61c717 100644 --- a/frontends/gtk/corewindow.c +++ b/frontends/gtk/corewindow.c @@ -662,7 +662,7 @@ static void nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds) { struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; - nsgtk_cw->drag_staus = ds; + nsgtk_cw->drag_status = ds; } @@ -682,6 +682,7 @@ static struct core_window_callback_table nsgtk_cw_cb_table = { nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw) { nsgtk_cw->cb_table = &nsgtk_cw_cb_table; + nsgtk_cw->drag_status = CORE_WINDOW_DRAG_NONE; /* input method setup */ nsgtk_cw->input_method = gtk_im_multicontext_new(); diff --git a/frontends/gtk/corewindow.h b/frontends/gtk/corewindow.h index 90bfd6193..6100e67ae 100644 --- a/frontends/gtk/corewindow.h +++ b/frontends/gtk/corewindow.h @@ -51,7 +51,7 @@ struct nsgtk_corewindow { /** mouse state */ struct nsgtk_corewindow_mouse mouse_state; /** drag status set by core */ - core_window_drag_status drag_staus; + core_window_drag_status drag_status; /** * callback to draw on drawable area of nsgtk core window diff --git a/frontends/gtk/global_history.c b/frontends/gtk/global_history.c index 66ba1a666..360eb4e1a 100644 --- a/frontends/gtk/global_history.c +++ b/frontends/gtk/global_history.c @@ -299,7 +299,7 @@ static nserror nsgtk_global_history_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsgtk_global_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/gtk/hotlist.c b/frontends/gtk/hotlist.c index 34a13772d..936573a0b 100644 --- a/frontends/gtk/hotlist.c +++ b/frontends/gtk/hotlist.c @@ -319,7 +319,7 @@ static nserror nsgtk_hotlist_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsgtk_hotlist_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/gtk/local_history.c b/frontends/gtk/local_history.c index 650cb4fb6..cc9580130 100644 --- a/frontends/gtk/local_history.c +++ b/frontends/gtk/local_history.c @@ -116,7 +116,7 @@ nsgtk_local_history_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r) lhw = (struct nsgtk_local_history_window *)nsgtk_cw; ctx.plot->clip(&ctx, r); - local_history_redraw(lhw->session, r->x0, r->y0, r, &ctx); + local_history_redraw(lhw->session, 0, 0, r, &ctx); return NSERROR_OK; } @@ -141,7 +141,7 @@ nsgtk_local_history_init(struct browser_window *bw, return res; } - ncwin = malloc(sizeof(struct nsgtk_local_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c index 78a6f6274..de5311e2e 100644 --- a/frontends/gtk/window.c +++ b/frontends/gtk/window.c @@ -1048,7 +1048,7 @@ static void gui_window_set_status(struct gui_window *g, const char *text) * content is shown. The GTK implementation scrolls the contents so * the specified point in the content is at the top of the viewport. * - * \param gw gui window to scroll + * \param g gui window to scroll * \param rect The rectangle to ensure is shown. * \return NSERROR_OK on success or apropriate error code. */ diff --git a/frontends/monkey/401login.c b/frontends/monkey/401login.c index 8b4d33d7d..090f18984 100644 --- a/frontends/monkey/401login.c +++ b/frontends/monkey/401login.c @@ -24,11 +24,11 @@ #include "monkey/401login.h" typedef struct monkey401 { - struct monkey401 *r_next, *r_prev; - uint32_t num; - lwc_string *host; /* Ignore */ - nserror (*cb)(bool,void*); - void *pw; + struct monkey401 *r_next, *r_prev; + uint32_t num; + lwc_string *host; /* Ignore */ + nserror (*cb)(bool,void*); + void *pw; } monkey401_t; static monkey401_t *m4_ring = NULL; @@ -37,19 +37,19 @@ static uint32_t m4_ctr = 0; void gui_401login_open(nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw) { - monkey401_t *m4t = calloc(sizeof(*m4t), 1); - if (m4t == NULL) { - cb(false, cbpw); - return; - } - m4t->cb = cb; - m4t->pw = cbpw; - m4t->num = m4_ctr++; + monkey401_t *m4t = calloc(sizeof(*m4t), 1); + if (m4t == NULL) { + cb(false, cbpw); + return; + } + m4t->cb = cb; + m4t->pw = cbpw; + m4t->num = m4_ctr++; - RING_INSERT(m4_ring, m4t); + RING_INSERT(m4_ring, m4t); - fprintf(stdout, "401LOGIN OPEN M4 %u URL %s REALM %s\n", - m4t->num, nsurl_access(url), realm); + fprintf(stdout, "401LOGIN OPEN M4 %u URL %s REALM %s\n", + m4t->num, nsurl_access(url), realm); } diff --git a/frontends/monkey/bitmap.c b/frontends/monkey/bitmap.c index 3313e1123..83b8566b6 100644 --- a/frontends/monkey/bitmap.c +++ b/frontends/monkey/bitmap.c @@ -26,125 +26,125 @@ #include "monkey/bitmap.h" struct bitmap { - void *ptr; - size_t rowstride; - int width; - int height; - unsigned int state; + void *ptr; + size_t rowstride; + int width; + int height; + unsigned int state; }; static void *bitmap_create(int width, int height, unsigned int state) { - struct bitmap *ret = calloc(sizeof(*ret), 1); - if (ret == NULL) - return NULL; + struct bitmap *ret = calloc(sizeof(*ret), 1); + if (ret == NULL) + return NULL; - ret->width = width; - ret->height = height; - ret->state = state; + ret->width = width; + ret->height = height; + ret->state = state; - ret->ptr = calloc(width, height * 4); + ret->ptr = calloc(width, height * 4); - if (ret->ptr == NULL) { - free(ret); - return NULL; - } + if (ret->ptr == NULL) { + free(ret); + return NULL; + } - return ret; + return ret; } static void bitmap_destroy(void *bitmap) { - struct bitmap *bmap = bitmap; - free(bmap->ptr); - free(bmap); + struct bitmap *bmap = bitmap; + free(bmap->ptr); + free(bmap); } static void bitmap_set_opaque(void *bitmap, bool opaque) { - struct bitmap *bmap = bitmap; + struct bitmap *bmap = bitmap; - if (opaque) - bmap->state |= (BITMAP_OPAQUE); - else - bmap->state &= ~(BITMAP_OPAQUE); + if (opaque) + bmap->state |= (BITMAP_OPAQUE); + else + bmap->state &= ~(BITMAP_OPAQUE); } static bool bitmap_test_opaque(void *bitmap) { - return false; + return false; } static bool bitmap_get_opaque(void *bitmap) { - struct bitmap *bmap = bitmap; + struct bitmap *bmap = bitmap; - return (bmap->state & BITMAP_OPAQUE) == BITMAP_OPAQUE; + return (bmap->state & BITMAP_OPAQUE) == BITMAP_OPAQUE; } static unsigned char *bitmap_get_buffer(void *bitmap) { - struct bitmap *bmap = bitmap; + struct bitmap *bmap = bitmap; - return (unsigned char *)(bmap->ptr); + return (unsigned char *)(bmap->ptr); } static size_t bitmap_get_rowstride(void *bitmap) { - struct bitmap *bmap = bitmap; - return bmap->width * 4; + struct bitmap *bmap = bitmap; + return bmap->width * 4; } static size_t bitmap_get_bpp(void *bitmap) { - /* OMG?! */ - return 4; + /* OMG?! */ + return 4; } static bool bitmap_save(void *bitmap, const char *path, unsigned flags) { - return true; + return true; } static void bitmap_modified(void *bitmap) { - struct bitmap *bmap = bitmap; - bmap->state |= BITMAP_MODIFIED; + struct bitmap *bmap = bitmap; + bmap->state |= BITMAP_MODIFIED; } static int bitmap_get_width(void *bitmap) { - struct bitmap *bmap = bitmap; - return bmap->width; + struct bitmap *bmap = bitmap; + return bmap->width; } static int bitmap_get_height(void *bitmap) { - struct bitmap *bmap = bitmap; - return bmap->height; + struct bitmap *bmap = bitmap; + return bmap->height; } static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content) { - fprintf(stdout, "GENERIC BITMAP RENDER\n"); - return NSERROR_OK; + fprintf(stdout, "GENERIC BITMAP RENDER\n"); + return NSERROR_OK; } static struct gui_bitmap_table bitmap_table = { - .create = bitmap_create, - .destroy = bitmap_destroy, - .set_opaque = bitmap_set_opaque, - .get_opaque = bitmap_get_opaque, - .test_opaque = bitmap_test_opaque, - .get_buffer = bitmap_get_buffer, - .get_rowstride = bitmap_get_rowstride, - .get_width = bitmap_get_width, - .get_height = bitmap_get_height, - .get_bpp = bitmap_get_bpp, - .save = bitmap_save, - .modified = bitmap_modified, - .render = bitmap_render, + .create = bitmap_create, + .destroy = bitmap_destroy, + .set_opaque = bitmap_set_opaque, + .get_opaque = bitmap_get_opaque, + .test_opaque = bitmap_test_opaque, + .get_buffer = bitmap_get_buffer, + .get_rowstride = bitmap_get_rowstride, + .get_width = bitmap_get_width, + .get_height = bitmap_get_height, + .get_bpp = bitmap_get_bpp, + .save = bitmap_save, + .modified = bitmap_modified, + .render = bitmap_render, }; struct gui_bitmap_table *monkey_bitmap_table = &bitmap_table; diff --git a/frontends/monkey/browser.c b/frontends/monkey/browser.c index 93360aa29..16d33010d 100644 --- a/frontends/monkey/browser.c +++ b/frontends/monkey/browser.c @@ -42,71 +42,71 @@ static struct gui_window *gw_ring = NULL; /* exported function documented in monkey/browser.h */ nserror monkey_warn_user(const char *warning, const char *detail) { - fprintf(stderr, "WARN %s %s\n", warning, detail); - return NSERROR_OK; + fprintf(stderr, "WARN %s %s\n", warning, detail); + return NSERROR_OK; } struct gui_window * monkey_find_window_by_num(uint32_t win_num) { - struct gui_window *ret = NULL; + struct gui_window *ret = NULL; - RING_ITERATE_START(struct gui_window, gw_ring, c_ring) { - if (c_ring->win_num == win_num) { - ret = c_ring; - RING_ITERATE_STOP(gw_ring, c_ring); - } - } RING_ITERATE_END(gw_ring, c_ring); + RING_ITERATE_START(struct gui_window, gw_ring, c_ring) { + if (c_ring->win_num == win_num) { + ret = c_ring; + RING_ITERATE_STOP(gw_ring, c_ring); + } + } RING_ITERATE_END(gw_ring, c_ring); - return ret; + return ret; } void monkey_kill_browser_windows(void) { - while (gw_ring != NULL) { - browser_window_destroy(gw_ring->bw); - } + while (gw_ring != NULL) { + browser_window_destroy(gw_ring->bw); + } } static struct gui_window * gui_window_create(struct browser_window *bw, - struct gui_window *existing, - gui_window_create_flags flags) + struct gui_window *existing, + gui_window_create_flags flags) { - struct gui_window *ret = calloc(sizeof(*ret), 1); - if (ret == NULL) - return NULL; + struct gui_window *ret = calloc(sizeof(*ret), 1); + if (ret == NULL) + return NULL; - ret->win_num = win_ctr++; - ret->bw = bw; + ret->win_num = win_ctr++; + ret->bw = bw; - ret->width = 800; - ret->height = 600; + ret->width = 800; + ret->height = 600; - fprintf(stdout, "WINDOW NEW WIN %u FOR %p EXISTING %p NEWTAB %s CLONE %s\n", - ret->win_num, bw, existing, flags & GW_CREATE_TAB ? "TRUE" : "FALSE", - flags & GW_CREATE_CLONE ? "TRUE" : "FALSE"); - fprintf(stdout, "WINDOW SIZE WIN %u WIDTH %d HEIGHT %d\n", - ret->win_num, ret->width, ret->height); + fprintf(stdout, "WINDOW NEW WIN %u FOR %p EXISTING %p NEWTAB %s CLONE %s\n", + ret->win_num, bw, existing, flags & GW_CREATE_TAB ? "TRUE" : "FALSE", + flags & GW_CREATE_CLONE ? "TRUE" : "FALSE"); + fprintf(stdout, "WINDOW SIZE WIN %u WIDTH %d HEIGHT %d\n", + ret->win_num, ret->width, ret->height); - RING_INSERT(gw_ring, ret); + RING_INSERT(gw_ring, ret); - return ret; + return ret; } static void gui_window_destroy(struct gui_window *g) { - fprintf(stdout, "WINDOW DESTROY WIN %u\n", g->win_num); - RING_REMOVE(gw_ring, g); - free(g); + fprintf(stdout, "WINDOW DESTROY WIN %u\n", g->win_num); + RING_REMOVE(gw_ring, g); + free(g); } static void gui_window_set_title(struct gui_window *g, const char *title) { - fprintf(stdout, "WINDOW TITLE WIN %u STR %s\n", g->win_num, title); + fprintf(stdout, "WINDOW TITLE WIN %u STR %s\n", g->win_num, title); } /** @@ -122,36 +122,36 @@ static nserror gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bool scaled) { - fprintf(stdout, "WINDOW GET_DIMENSIONS WIN %u WIDTH %d HEIGHT %d\n", - g->win_num, g->width, g->height); - *width = g->width; - *height = g->height; + fprintf(stdout, "WINDOW GET_DIMENSIONS WIN %u WIDTH %d HEIGHT %d\n", + g->win_num, g->width, g->height); + *width = g->width; + *height = g->height; - return NSERROR_OK; + return NSERROR_OK; } static void gui_window_new_content(struct gui_window *g) { - fprintf(stdout, "WINDOW NEW_CONTENT WIN %u\n", g->win_num); + fprintf(stdout, "WINDOW NEW_CONTENT WIN %u\n", g->win_num); } static void gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon) { - fprintf(stdout, "WINDOW NEW_ICON WIN %u\n", g->win_num); + fprintf(stdout, "WINDOW NEW_ICON WIN %u\n", g->win_num); } static void gui_window_start_throbber(struct gui_window *g) { - fprintf(stdout, "WINDOW START_THROBBER WIN %u\n", g->win_num); + fprintf(stdout, "WINDOW START_THROBBER WIN %u\n", g->win_num); } static void gui_window_stop_throbber(struct gui_window *g) { - fprintf(stdout, "WINDOW STOP_THROBBER WIN %u\n", g->win_num); + fprintf(stdout, "WINDOW STOP_THROBBER WIN %u\n", g->win_num); } @@ -168,12 +168,12 @@ gui_window_stop_throbber(struct gui_window *g) static nserror gui_window_set_scroll(struct gui_window *gw, const struct rect *rect) { - gw->scrollx = rect->x0; - gw->scrolly = rect->y0; + gw->scrollx = rect->x0; + gw->scrolly = rect->y0; - fprintf(stdout, "WINDOW SET_SCROLL WIN %u X0 %d Y0 %d X1 %d Y1 %d\n", - gw->win_num, rect->x0, rect->y0, rect->x1, rect->y1); - return NSERROR_OK; + fprintf(stdout, "WINDOW SET_SCROLL WIN %u X %d Y %d\n", + gw->win_num, rect->x0, rect->y0); + return NSERROR_OK; } @@ -204,144 +204,144 @@ monkey_window_invalidate_area(struct gui_window *gw, const struct rect *rect) static void gui_window_update_extent(struct gui_window *g) { - int width, height; + int width, height; - if (browser_window_get_extents(g->bw, false, &width, &height) != NSERROR_OK) - return; + if (browser_window_get_extents(g->bw, false, &width, &height) != NSERROR_OK) + return; - fprintf(stdout, "WINDOW UPDATE_EXTENT WIN %u WIDTH %d HEIGHT %d\n", - g->win_num, width, height); + fprintf(stdout, "WINDOW UPDATE_EXTENT WIN %u WIDTH %d HEIGHT %d\n", + g->win_num, width, height); } static void gui_window_set_status(struct gui_window *g, const char *text) { - fprintf(stdout, "WINDOW SET_STATUS WIN %u STR %s\n", g->win_num, text); + fprintf(stdout, "WINDOW SET_STATUS WIN %u STR %s\n", g->win_num, text); } static void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) { - const char *ptr_name = "UNKNOWN"; + const char *ptr_name = "UNKNOWN"; - switch (shape) { - case GUI_POINTER_POINT: - ptr_name = "POINT"; - break; - case GUI_POINTER_CARET: - ptr_name = "CARET"; - break; - case GUI_POINTER_UP: - ptr_name = "UP"; - break; - case GUI_POINTER_DOWN: - ptr_name = "DOWN"; - break; - case GUI_POINTER_LEFT: - ptr_name = "LEFT"; - break; - case GUI_POINTER_RIGHT: - ptr_name = "RIGHT"; - break; - case GUI_POINTER_LD: - ptr_name = "LD"; - break; - case GUI_POINTER_RD: - ptr_name = "RD"; - break; - case GUI_POINTER_LU: - ptr_name = "LU"; - break; - case GUI_POINTER_RU: - ptr_name = "RU"; - break; - case GUI_POINTER_CROSS: - ptr_name = "CROSS"; - break; - case GUI_POINTER_MOVE: - ptr_name = "MOVE"; - break; - case GUI_POINTER_WAIT: - ptr_name = "WAIT"; - break; - case GUI_POINTER_HELP: - ptr_name = "HELP"; - break; - case GUI_POINTER_MENU: - ptr_name = "MENU"; - break; - case GUI_POINTER_PROGRESS: - ptr_name = "PROGRESS"; - break; - case GUI_POINTER_NO_DROP: - ptr_name = "NO_DROP"; - break; - case GUI_POINTER_NOT_ALLOWED: - ptr_name = "NOT_ALLOWED"; - break; - case GUI_POINTER_DEFAULT: - ptr_name = "DEFAULT"; - break; - default: - break; - } - fprintf(stdout, "WINDOW SET_POINTER WIN %u POINTER %s\n", g->win_num, ptr_name); + switch (shape) { + case GUI_POINTER_POINT: + ptr_name = "POINT"; + break; + case GUI_POINTER_CARET: + ptr_name = "CARET"; + break; + case GUI_POINTER_UP: + ptr_name = "UP"; + break; + case GUI_POINTER_DOWN: + ptr_name = "DOWN"; + break; + case GUI_POINTER_LEFT: + ptr_name = "LEFT"; + break; + case GUI_POINTER_RIGHT: + ptr_name = "RIGHT"; + break; + case GUI_POINTER_LD: + ptr_name = "LD"; + break; + case GUI_POINTER_RD: + ptr_name = "RD"; + break; + case GUI_POINTER_LU: + ptr_name = "LU"; + break; + case GUI_POINTER_RU: + ptr_name = "RU"; + break; + case GUI_POINTER_CROSS: + ptr_name = "CROSS"; + break; + case GUI_POINTER_MOVE: + ptr_name = "MOVE"; + break; + case GUI_POINTER_WAIT: + ptr_name = "WAIT"; + break; + case GUI_POINTER_HELP: + ptr_name = "HELP"; + break; + case GUI_POINTER_MENU: + ptr_name = "MENU"; + break; + case GUI_POINTER_PROGRESS: + ptr_name = "PROGRESS"; + break; + case GUI_POINTER_NO_DROP: + ptr_name = "NO_DROP"; + break; + case GUI_POINTER_NOT_ALLOWED: + ptr_name = "NOT_ALLOWED"; + break; + case GUI_POINTER_DEFAULT: + ptr_name = "DEFAULT"; + break; + default: + break; + } + fprintf(stdout, "WINDOW SET_POINTER WIN %u POINTER %s\n", g->win_num, ptr_name); } static nserror gui_window_set_url(struct gui_window *g, nsurl *url) { - fprintf(stdout, "WINDOW SET_URL WIN %u URL %s\n", g->win_num, nsurl_access(url)); - return NSERROR_OK; + fprintf(stdout, "WINDOW SET_URL WIN %u URL %s\n", g->win_num, nsurl_access(url)); + return NSERROR_OK; } static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) { - fprintf(stdout, "WINDOW GET_SCROLL WIN %u X %d Y %d\n", - g->win_num, g->scrollx, g->scrolly); - *sx = g->scrollx; - *sy = g->scrolly; - return true; + fprintf(stdout, "WINDOW GET_SCROLL WIN %u X %d Y %d\n", + g->win_num, g->scrollx, g->scrolly); + *sx = g->scrollx; + *sy = g->scrolly; + return true; } static bool gui_window_scroll_start(struct gui_window *g) { - fprintf(stdout, "WINDOW SCROLL_START WIN %u\n", g->win_num); - g->scrollx = g->scrolly = 0; - return true; + fprintf(stdout, "WINDOW SCROLL_START WIN %u\n", g->win_num); + g->scrollx = g->scrolly = 0; + return true; } static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, - const struct rect *clip) + const struct rect *clip) { - fprintf(stdout, "WINDOW PLACE_CARET WIN %u X %d Y %d HEIGHT %d\n", - g->win_num, x, y, height); + fprintf(stdout, "WINDOW PLACE_CARET WIN %u X %d Y %d HEIGHT %d\n", + g->win_num, x, y, height); } static void gui_window_remove_caret(struct gui_window *g) { - fprintf(stdout, "WINDOW REMOVE_CARET WIN %u\n", g->win_num); + fprintf(stdout, "WINDOW REMOVE_CARET WIN %u\n", g->win_num); } static bool gui_window_drag_start(struct gui_window *g, gui_drag_type type, const struct rect *rect) { - fprintf(stdout, "WINDOW SCROLL_START WIN %u TYPE %i\n", g->win_num, type); - return false; + fprintf(stdout, "WINDOW SCROLL_START WIN %u TYPE %i\n", g->win_num, type); + return false; } static nserror gui_window_save_link(struct gui_window *g, nsurl *url, const char *title) { - fprintf(stdout, "WINDOW SAVE_LINK WIN %u URL %s TITLE %s\n", - g->win_num, nsurl_access(url), title); - return NSERROR_OK; + fprintf(stdout, "WINDOW SAVE_LINK WIN %u URL %s TITLE %s\n", + g->win_num, nsurl_access(url), title); + return NSERROR_OK; } @@ -351,169 +351,169 @@ gui_window_save_link(struct gui_window *g, nsurl *url, const char *title) static void monkey_window_handle_new(int argc, char **argv) { - nsurl *url = NULL; - nserror error = NSERROR_OK; - - if (argc > 3) - return; - - if (argc == 3) { - error = nsurl_create(argv[2], &url); - } - if (error == NSERROR_OK) { - error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); - if (url != NULL) { - nsurl_unref(url); - } - } - if (error != NSERROR_OK) { - monkey_warn_user(messages_get_errorcode(error), 0); - } + nsurl *url = NULL; + nserror error = NSERROR_OK; + + if (argc > 3) + return; + + if (argc == 3) { + error = nsurl_create(argv[2], &url); + } + if (error == NSERROR_OK) { + error = browser_window_create(BW_CREATE_HISTORY, + url, + NULL, + NULL, + NULL); + if (url != NULL) { + nsurl_unref(url); + } + } + if (error != NSERROR_OK) { + monkey_warn_user(messages_get_errorcode(error), 0); + } } static void monkey_window_handle_destroy(int argc, char **argv) { - struct gui_window *gw; - uint32_t nr = atoi((argc > 2) ? argv[2] : "-1"); + struct gui_window *gw; + uint32_t nr = atoi((argc > 2) ? argv[2] : "-1"); - gw = monkey_find_window_by_num(nr); + gw = monkey_find_window_by_num(nr); - if (gw == NULL) { - fprintf(stdout, "ERROR WINDOW NUM BAD\n"); - } else { - browser_window_destroy(gw->bw); - } + if (gw == NULL) { + fprintf(stdout, "ERROR WINDOW NUM BAD\n"); + } else { + browser_window_destroy(gw->bw); + } } static void monkey_window_handle_go(int argc, char **argv) { - struct gui_window *gw; - nsurl *url; - nsurl *ref_url = NULL; - nserror error; + struct gui_window *gw; + nsurl *url; + nsurl *ref_url = NULL; + nserror error; - if (argc < 4 || argc > 5) { - fprintf(stdout, "ERROR WINDOW GO ARGS BAD\n"); - return; - } + if (argc < 4 || argc > 5) { + fprintf(stdout, "ERROR WINDOW GO ARGS BAD\n"); + return; + } - gw = monkey_find_window_by_num(atoi(argv[2])); + gw = monkey_find_window_by_num(atoi(argv[2])); - if (gw == NULL) { - fprintf(stdout, "ERROR WINDOW NUM BAD\n"); - return; - } - - error = nsurl_create(argv[3], &url); - if (error == NSERROR_OK) { - if (argc == 5) { - error = nsurl_create(argv[4], &ref_url); - } - - if (error == NSERROR_OK) { - error = browser_window_navigate(gw->bw, - url, - ref_url, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - if (ref_url != NULL) { - nsurl_unref(ref_url); - } - } - nsurl_unref(url); - } - - if (error != NSERROR_OK) { - monkey_warn_user(messages_get_errorcode(error), 0); - } + if (gw == NULL) { + fprintf(stdout, "ERROR WINDOW NUM BAD\n"); + return; + } + + error = nsurl_create(argv[3], &url); + if (error == NSERROR_OK) { + if (argc == 5) { + error = nsurl_create(argv[4], &ref_url); + } + + if (error == NSERROR_OK) { + error = browser_window_navigate(gw->bw, + url, + ref_url, + BW_NAVIGATE_HISTORY, + NULL, + NULL, + NULL); + if (ref_url != NULL) { + nsurl_unref(ref_url); + } + } + nsurl_unref(url); + } + + if (error != NSERROR_OK) { + monkey_warn_user(messages_get_errorcode(error), 0); + } } static void monkey_window_handle_redraw(int argc, char **argv) { - struct gui_window *gw; - struct rect clip; - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = monkey_plotters - }; + struct gui_window *gw; + struct rect clip; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = monkey_plotters + }; - if (argc != 3 && argc != 7) { - fprintf(stdout, "ERROR WINDOW REDRAW ARGS BAD\n"); - return; - } + if (argc != 3 && argc != 7) { + fprintf(stdout, "ERROR WINDOW REDRAW ARGS BAD\n"); + return; + } - gw = monkey_find_window_by_num(atoi(argv[2])); + gw = monkey_find_window_by_num(atoi(argv[2])); - if (gw == NULL) { - fprintf(stdout, "ERROR WINDOW NUM BAD\n"); - return; - } + if (gw == NULL) { + fprintf(stdout, "ERROR WINDOW NUM BAD\n"); + return; + } - clip.x0 = 0; - clip.y0 = 0; - clip.x1 = gw->width; - clip.y1 = gw->height; + clip.x0 = 0; + clip.y0 = 0; + clip.x1 = gw->width; + clip.y1 = gw->height; - if (argc == 7) { - clip.x0 = atoi(argv[3]); - clip.y0 = atoi(argv[4]); - clip.x1 = atoi(argv[5]); - clip.y1 = atoi(argv[6]); - } + if (argc == 7) { + clip.x0 = atoi(argv[3]); + clip.y0 = atoi(argv[4]); + clip.x1 = atoi(argv[5]); + clip.y1 = atoi(argv[6]); + } - LOG("Issue redraw"); - fprintf(stdout, "WINDOW REDRAW WIN %d START\n", atoi(argv[2])); - browser_window_redraw(gw->bw, gw->scrollx, gw->scrolly, &clip, &ctx); - fprintf(stdout, "WINDOW REDRAW WIN %d STOP\n", atoi(argv[2])); + LOG("Issue redraw"); + fprintf(stdout, "WINDOW REDRAW WIN %d START\n", atoi(argv[2])); + browser_window_redraw(gw->bw, gw->scrollx, gw->scrolly, &clip, &ctx); + fprintf(stdout, "WINDOW REDRAW WIN %d STOP\n", atoi(argv[2])); } static void monkey_window_handle_reload(int argc, char **argv) { - struct gui_window *gw; - if (argc != 3 && argc != 4) { - fprintf(stdout, "ERROR WINDOW RELOAD ARGS BAD\n"); - } + struct gui_window *gw; + if (argc != 3 && argc != 4) { + fprintf(stdout, "ERROR WINDOW RELOAD ARGS BAD\n"); + } - gw = monkey_find_window_by_num(atoi(argv[2])); + gw = monkey_find_window_by_num(atoi(argv[2])); - if (gw == NULL) { - fprintf(stdout, "ERROR WINDOW NUM BAD\n"); - } else { - browser_window_reload(gw->bw, argc == 4); - } + if (gw == NULL) { + fprintf(stdout, "ERROR WINDOW NUM BAD\n"); + } else { + browser_window_reload(gw->bw, argc == 4); + } } void monkey_window_handle_command(int argc, char **argv) { - if (argc == 1) - return; + if (argc == 1) + return; - if (strcmp(argv[1], "NEW") == 0) { - monkey_window_handle_new(argc, argv); - } else if (strcmp(argv[1], "DESTROY") == 0) { - monkey_window_handle_destroy(argc, argv); - } else if (strcmp(argv[1], "GO") == 0) { - monkey_window_handle_go(argc, argv); - } else if (strcmp(argv[1], "REDRAW") == 0) { - monkey_window_handle_redraw(argc, argv); - } else if (strcmp(argv[1], "RELOAD") == 0) { - monkey_window_handle_reload(argc, argv); - } else { - fprintf(stdout, "ERROR WINDOW COMMAND UNKNOWN %s\n", argv[1]); - } + if (strcmp(argv[1], "NEW") == 0) { + monkey_window_handle_new(argc, argv); + } else if (strcmp(argv[1], "DESTROY") == 0) { + monkey_window_handle_destroy(argc, argv); + } else if (strcmp(argv[1], "GO") == 0) { + monkey_window_handle_go(argc, argv); + } else if (strcmp(argv[1], "REDRAW") == 0) { + monkey_window_handle_redraw(argc, argv); + } else if (strcmp(argv[1], "RELOAD") == 0) { + monkey_window_handle_reload(argc, argv); + } else { + fprintf(stdout, "ERROR WINDOW COMMAND UNKNOWN %s\n", argv[1]); + } } diff --git a/frontends/monkey/browser.h b/frontends/monkey/browser.h index 2b0340211..8cbbb947d 100644 --- a/frontends/monkey/browser.h +++ b/frontends/monkey/browser.h @@ -25,16 +25,16 @@ extern struct gui_window_table *monkey_window_table; extern struct gui_download_table *monkey_download_table; struct gui_window { - struct gui_window *r_next; - struct gui_window *r_prev; + struct gui_window *r_next; + struct gui_window *r_prev; - uint32_t win_num; - struct browser_window *bw; + uint32_t win_num; + struct browser_window *bw; - int width, height; - int scrollx, scrolly; + int width, height; + int scrollx, scrolly; - char *host; /* Ignore this, it's in case RING*() gets debugging for fetchers */ + char *host; /* Ignore this, it's in case RING*() gets debugging for fetchers */ }; diff --git a/frontends/monkey/cert.c b/frontends/monkey/cert.c index 710e71098..a19975527 100644 --- a/frontends/monkey/cert.c +++ b/frontends/monkey/cert.c @@ -25,11 +25,11 @@ #include "monkey/cert.h" typedef struct monkey_cert { - struct monkey_cert *r_next, *r_prev; - uint32_t num; - char *host; /* Ignore */ - nserror (*cb)(bool,void*); - void *pw; + struct monkey_cert *r_next, *r_prev; + uint32_t num; + char *host; /* Ignore */ + nserror (*cb)(bool,void*); + void *pw; } monkey_cert_t; static monkey_cert_t *cert_ring = NULL; @@ -40,20 +40,20 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw) { - monkey_cert_t *m4t = calloc(sizeof(*m4t), 1); - if (m4t == NULL) { - return NSERROR_NOMEM; - } - m4t->cb = cb; - m4t->pw = cbpw; - m4t->num = cert_ctr++; + monkey_cert_t *m4t = calloc(sizeof(*m4t), 1); + if (m4t == NULL) { + return NSERROR_NOMEM; + } + m4t->cb = cb; + m4t->pw = cbpw; + m4t->num = cert_ctr++; - RING_INSERT(cert_ring, m4t); + RING_INSERT(cert_ring, m4t); - fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n", - m4t->num, nsurl_access(url)); + fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n", + m4t->num, nsurl_access(url)); - return NSERROR_OK; + return NSERROR_OK; } diff --git a/frontends/monkey/dispatch.c b/frontends/monkey/dispatch.c index 563534d64..b531f05f9 100644 --- a/frontends/monkey/dispatch.c +++ b/frontends/monkey/dispatch.c @@ -28,9 +28,9 @@ #include "monkey/dispatch.h" typedef struct cmdhandler { - struct cmdhandler *r_next, *r_prev; - const char *cmd; - handle_command_fn fn; + struct cmdhandler *r_next, *r_prev; + const char *cmd; + handle_command_fn fn; } monkey_cmdhandler_t; static monkey_cmdhandler_t *handler_ring = NULL; @@ -38,68 +38,68 @@ static monkey_cmdhandler_t *handler_ring = NULL; nserror monkey_register_handler(const char *cmd, handle_command_fn fn) { - monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1); - if (ret == NULL) { - LOG("Unable to allocate handler"); - return NSERROR_NOMEM; - } - ret->cmd = strdup(cmd); - ret->fn = fn; - RING_INSERT(handler_ring, ret); - return NSERROR_OK; + monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1); + if (ret == NULL) { + LOG("Unable to allocate handler"); + return NSERROR_NOMEM; + } + ret->cmd = strdup(cmd); + ret->fn = fn; + RING_INSERT(handler_ring, ret); + return NSERROR_OK; } void monkey_process_command(void) { - char buffer[PATH_MAX]; - int argc = 0; - char **argv = NULL; - char *p, *r = NULL; - handle_command_fn fn = NULL; - char **nargv; + char buffer[PATH_MAX]; + int argc = 0; + char **argv = NULL; + char *p, *r = NULL; + handle_command_fn fn = NULL; + char **nargv; - if (fgets(buffer, PATH_MAX, stdin) == NULL) { - /* end of input or read error so issue QUIT */ - sprintf(buffer, "QUIT\n"); - } + if (fgets(buffer, PATH_MAX, stdin) == NULL) { + /* end of input or read error so issue QUIT */ + sprintf(buffer, "QUIT\n"); + } - /* remove newline */ - buffer[strlen(buffer) - 1] = '\0'; + /* remove newline */ + buffer[strlen(buffer) - 1] = '\0'; - argv = malloc(sizeof *argv); - if (argv == NULL) { - return; - } - argc = 1; - *argv = buffer; + argv = malloc(sizeof *argv); + if (argv == NULL) { + return; + } + argc = 1; + *argv = buffer; - for (p = r = buffer; *p != '\0'; p++) { - if (*p == ' ') { - nargv = realloc(argv, sizeof(*argv) * (argc + 1)); - if (nargv == NULL) { - /* reallocation of argument vector failed, try using what is - * already processed. - */ - break; - } else { - argv = nargv; - } - argv[argc++] = r = p + 1; - *p = '\0'; - } - } + for (p = r = buffer; *p != '\0'; p++) { + if (*p == ' ') { + nargv = realloc(argv, sizeof(*argv) * (argc + 1)); + if (nargv == NULL) { + /* reallocation of argument vector failed, try using what is + * already processed. + */ + break; + } else { + argv = nargv; + } + argv[argc++] = r = p + 1; + *p = '\0'; + } + } - RING_ITERATE_START(monkey_cmdhandler_t, handler_ring, handler) { - if (strcmp(argv[0], handler->cmd) == 0) { - fn = handler->fn; - RING_ITERATE_STOP(handler_ring, handler); - } - } RING_ITERATE_END(handler_ring, handler); + RING_ITERATE_START(monkey_cmdhandler_t, handler_ring, handler) { + if (strcmp(argv[0], handler->cmd) == 0) { + fn = handler->fn; + RING_ITERATE_STOP(handler_ring, handler); + } + } RING_ITERATE_END(handler_ring, handler); - if (fn != NULL) { - fn(argc, argv); - } + if (fn != NULL) { + fn(argc, argv); + } - free(argv); + free(argv); } diff --git a/frontends/monkey/download.c b/frontends/monkey/download.c index f2e1cbfbf..5c9ce1b53 100644 --- a/frontends/monkey/download.c +++ b/frontends/monkey/download.c @@ -30,11 +30,11 @@ static uint32_t dwin_ctr = 0; struct gui_download_window { - struct gui_download_window *r_next; - struct gui_download_window *r_prev; - struct gui_window *g; - uint32_t dwin_num; - char *host; /* ignore */ + struct gui_download_window *r_next; + struct gui_download_window *r_prev; + struct gui_window *g; + uint32_t dwin_num; + char *host; /* ignore */ }; static struct gui_download_window *dw_ring = NULL; @@ -43,44 +43,44 @@ static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *parent) { - struct gui_download_window *ret = calloc(sizeof(*ret), 1); - if (ret == NULL) - return NULL; - ret->g = parent; - ret->dwin_num = dwin_ctr++; + struct gui_download_window *ret = calloc(sizeof(*ret), 1); + if (ret == NULL) + return NULL; + ret->g = parent; + ret->dwin_num = dwin_ctr++; - RING_INSERT(dw_ring, ret); + RING_INSERT(dw_ring, ret); - fprintf(stdout, "DOWNLOAD_WINDOW CREATE DWIN %u WIN %u\n", - ret->dwin_num, parent->win_num); + fprintf(stdout, "DOWNLOAD_WINDOW CREATE DWIN %u WIN %u\n", + ret->dwin_num, parent->win_num); - return ret; + return ret; } static nserror gui_download_window_data(struct gui_download_window *dw, const char *data, unsigned int size) { - fprintf(stdout, "DOWNLOAD_WINDOW DATA DWIN %u SIZE %u DATA %s\n", - dw->dwin_num, size, data); - return NSERROR_OK; + fprintf(stdout, "DOWNLOAD_WINDOW DATA DWIN %u SIZE %u DATA %s\n", + dw->dwin_num, size, data); + return NSERROR_OK; } static void gui_download_window_error(struct gui_download_window *dw, const char *error_msg) { - fprintf(stdout, "DOWNLOAD_WINDOW ERROR DWIN %u ERROR %s\n", - dw->dwin_num, error_msg); + fprintf(stdout, "DOWNLOAD_WINDOW ERROR DWIN %u ERROR %s\n", + dw->dwin_num, error_msg); } static void gui_download_window_done(struct gui_download_window *dw) { - fprintf(stdout, "DOWNLOAD_WINDOW DONE DWIN %u\n", - dw->dwin_num); - RING_REMOVE(dw_ring, dw); - free(dw); + fprintf(stdout, "DOWNLOAD_WINDOW DONE DWIN %u\n", + dw->dwin_num); + RING_REMOVE(dw_ring, dw); + free(dw); } static struct gui_download_table download_table = { diff --git a/frontends/monkey/farmer.py b/frontends/monkey/farmer.py new file mode 100644 index 000000000..d4b4b1e21 --- /dev/null +++ b/frontends/monkey/farmer.py @@ -0,0 +1,363 @@ +#!/usr/bin/python + +# Copyright 2017 Daniel Silverstone <dsilvers@digital-scurf.org> +# +# This file is part of NetSurf, http://www.netsurf-browser.org/ +# +# NetSurf is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# NetSurf is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Monkey Farmer + +The monkey farmer is a wrapper around `nsmonkey` which can be used to simplify +access to the monkey behaviours and ultimately to write useful tests in an +expressive but not overcomplicated DSLish way. Tests are, ultimately, still +Python code. + +""" + +import asyncore +import os +import socket +import subprocess +import time + +#monkey_cmd = ['./nsmonkey', '--accept_language=fr'] +monkey_cmd = ['./nsmonkey'] + +class MonkeyFarmer(asyncore.dispatcher): + def __init__(self, online, quiet=False): + (mine, monkeys) = socket.socketpair() + + asyncore.dispatcher.__init__(self, sock=mine) + + self.monkey = subprocess.Popen( + monkey_cmd, + stdin=monkeys, + stdout=monkeys, + close_fds=[mine]) + + monkeys.close() + + self.buffer = "" + self.incoming = "" + self.lines = [] + self.scheduled = [] + self.deadmonkey = False + self.online = online + self.quiet = quiet + + def handle_connect(self): + pass + + def handle_read(self): + got = self.recv(8192) + if got == "" or got is None: + self.deadmonkey = True + return + self.incoming += got + if "\n" in self.incoming: + lines = self.incoming.split("\n") + self.incoming = lines.pop() + self.lines = lines + + def writable(self): + return (len(self.buffer) > 0) + + def handle_write(self): + sent = self.send(self.buffer) + self.buffer = self.buffer[sent:] + + def tell_monkey(self, *args): + cmd = (" ".join(args)) + if not self.quiet: + print ">>> %s" % cmd + self.buffer += "%s\n" % cmd + + def monkey_says(self, line): + if not self.quiet: + print "<<< %s" % line + self.online(line) + + def schedule_event(self, event, secs=None, when=None): + assert(secs is not None or when is not None) + if when is None: + when = time.time() + secs + self.scheduled.append((when, event)) + self.scheduled.sort(lambda a,b: cmp(a[0],b[0])) + + def unschedule_event(self, event): + self.scheduled = [x for x in self.scheduled if x[1] != event] + + def loop(self, once=False): + if len(self.lines) > 0: + self.monkey_says(self.lines.pop(0)) + if once: + return + while not self.deadmonkey: + now = time.time() + while len(self.scheduled) > 0 and now >= self.scheduled[0][0]: + func = self.scheduled[0][1] + self.scheduled.pop(0) + func(self) + now = time.time() + if len(self.scheduled) > 0: + next = self.scheduled[0][0] + asyncore.loop(timeout=next-now, count=1) + else: + asyncore.loop(count=1) + if len(self.lines) > 0: + self.monkey_says(self.lines.pop(0)) + if once: + break + +class Browser: + def __init__(self, quiet=False): + self.farmer = MonkeyFarmer(online=self.on_monkey_line, quiet=quiet) + self.windows = {} + self.current_draw_target = None + + def pass_options(self, *opts): + if len(opts) > 0: + self.farmer.tell_monkey("OPTIONS " + (" ".join(opts))) + + def on_monkey_line(self, line): + parts = line.split(" ") + handler = getattr(self, "handle_" + parts[0], None) + if handler is not None: + handler(*parts[1:]) + + def quit(self): + self.farmer.tell_monkey("QUIT") + + def quit_and_wait(self): + self.quit() + self.farmer.loop() + + def handle_GENERIC(self, what, *args): + pass + + def handle_WINDOW(self, action, _win, winid, *args): + if action == "NEW": + new_win = BrowserWindow(self, winid, *args) + self.windows[winid] = new_win + else: + win = self.windows.get(winid, None) + if win is None: + print " Unknown window id %s" % winid + else: + win.handle(action, *args) + + def handle_PLOT(self, *args): + if self.current_draw_target is not None: + self.current_draw_target.handle_plot(*args) + + def new_window(self, url=None): + if url is None: + self.farmer.tell_monkey("WINDOW NEW") + else: + self.farmer.tell_monkey("WINDOW NEW %s" % url) + wins_known = set(self.windows.keys()) + while len(set(self.windows.keys()).difference(wins_known)) == 0: + self.farmer.loop(once=True) + poss_wins = set(self.windows.keys()).difference(wins_known) + return self.windows[poss_wins.pop()] + + +class BrowserWindow: + def __init__(self, browser, winid, _for, coreid, _existing, otherid, _newtab, newtab, _clone, clone): + self.alive = True + self.browser = browser + self.winid = winid + self.coreid = coreid + self.existing = browser.windows.get(otherid, None) + self.newtab = newtab == "TRUE" + self.clone = clone == "TRUE" + self.width = 0 + self.height = 0 + self.title = "" + self.throbbing = False + self.scrollx = 0 + self.scrolly = 0 + self.content_width = 0 + self.content_height = 0 + self.status = "" + self.pointer = "" + self.scale = 1.0 + self.url = "" + self.plotted = [] + self.plotting = False + + def kill(self): + self.browser.farmer.tell_monkey("WINDOW DESTROY %s" % self.winid) + + def go(self, url, referer = None): + if referer is None: + self.browser.farmer.tell_monkey("WINDOW GO %s %s" % ( + self.winid, url)) + else: + self.browser.farmer.tell_monkey("WINDOW GO %s %s %s" % ( + self.winid, url, referer)) + + def reload(self): + self.browser.farmer.tell_monkey("WINDOW RELOAD %s" % self.winid) + + def redraw(self, coords=None): + if coords is None: + self.browser.farmer.tell_monkey("WINDOW REDRAW %s" % self.winid) + else: + self.browser.farmer.tell_monkey("WINDOW REDRAW %s %s" % ( + self.winid, (" ".join(coords)))) + + def handle(self, action, *args): + handler = getattr(self, "handle_window_" + action, None) + if handler is not None: + handler(*args) + + def handle_window_SIZE(self, _width, width, _height, height): + self.width = int(width) + self.height = int(height) + + def handle_window_DESTROY(self): + self.alive = False + + def handle_window_TITLE(self, _str, *title): + self.title = " ".join(title) + + def handle_window_REDRAW(self): + pass + + def handle_window_GET_DIMENSIONS(self, _width, width, _height, height): + self.width = width + self.height = height + + def handle_window_NEW_CONTENT(self): + pass + + def handle_window_NEW_ICON(self): + pass + + def handle_window_START_THROBBER(self): + self.throbbing = True + + def handle_window_STOP_THROBBER(self): + self.throbbing = False + + def handle_window_SET_SCROLL(self, _x, x, _y, y): + self.scrollx = int(x) + self.scrolly = int(y) + + def handle_window_UPDATE_BOX(self, _x, x, _y, y, _width, width, _height, height): + x = int(x) + y = int(y) + width = int(width) + height = int(height) + pass + + def handle_window_UPDATE_EXTENT(self, _width, width, _height, height): + self.content_width = int(width) + self.content_height = int(height) + + def handle_window_SET_STATUS(self, _str, *status): + self.status = (" ".join(status)) + + def handle_window_SET_POINTER(self, _ptr, ptr): + self.pointer = ptr + + def handle_window_SET_SCALE(self, _scale, scale): + self.scale = float(scale) + + def handle_window_SET_URL(self, _url, url): + self.url = url + + def handle_window_GET_SCROLL(self, _x, x, _y, y): + self.scrollx = int(x) + self.scrolly = int(y) + + def handle_window_SCROLL_START(self): + self.scrollx = 0 + self.scrolly = 0 + + def handle_window_REDRAW(self, act): + if act == "START": + self.browser.current_draw_target = self + self.plotted = [] + self.plotting = True + else: + self.browser.current_draw_target = None + self.plotting = False + + def load_page(self, url=None, referer=None): + if url is not None: + self.go(url, referer) + self.wait_loaded() + + def reload(self): + self.browser.farmer.tell_monkey("WINDOW RELOAD %s" % self.winid) + self.wait_loaded() + + def wait_loaded(self): + while not self.throbbing: + self.browser.farmer.loop(once=True) + while self.throbbing: + self.browser.farmer.loop(once=True) + + def handle_plot(self, *args): + self.plotted.append(args) + + def redraw(self, coords=None): + if coords is None: + self.browser.farmer.tell_monkey("WINDOW REDRAW %s" % self.winid) + else: + self.browser.farmer.tell_monkey("WINDOW REDRAW %s %s" % ( + self.winid, (" ".join(coords)))) + while not self.plotting: + self.browser.farmer.loop(once=True) + while self.plotting: + self.browser.farmer.loop(once=True) + return self.plotted + + +# Simple test is as follows... + +browser = Browser(quiet=True) + +win = browser.new_window() + +fname = "test/js/inline-doc-write-simple.html" +full_fname = os.path.join(os.getcwd(), fname) + +browser.pass_options("--enable_javascript=0") +win.load_page("file://" + full_fname) + +print("Loaded, URL is %s" % win.url) + +cmds = win.redraw() +print("Received %d plot commands" % len(cmds)) +for cmd in cmds: + if cmd[0] == "TEXT": + print "%s %s -> %s" % (cmd[2], cmd[4], (" ".join(cmd[6:]))) + + +browser.pass_options("--enable_javascript=1") +win.load_page("file://" + full_fname) + +print("Loaded, URL is %s" % win.url) + +cmds = win.redraw() +print("Received %d plot commands" % len(cmds)) +for cmd in cmds: + if cmd[0] == "TEXT": + print "%s %s -> %s" % (cmd[2], cmd[4], (" ".join(cmd[6:]))) + +browser.quit_and_wait() diff --git a/frontends/monkey/fetch.c b/frontends/monkey/fetch.c index 4985329db..256d79b59 100644 --- a/frontends/monkey/fetch.c +++ b/frontends/monkey/fetch.c @@ -36,18 +36,18 @@ extern char **respaths; static nsurl *gui_get_resource_url(const char *path) { - char buf[PATH_MAX]; - nsurl *url = NULL; + char buf[PATH_MAX]; + nsurl *url = NULL; - netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url); + netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url); - return url; + return url; } static struct gui_fetch_table fetch_table = { - .filetype = monkey_fetch_filetype, + .filetype = monkey_fetch_filetype, - .get_resource_url = gui_get_resource_url, + .get_resource_url = gui_get_resource_url, }; struct gui_fetch_table *monkey_fetch_table = &fetch_table; diff --git a/frontends/monkey/layout.c b/frontends/monkey/layout.c index 4bcc51b68..7b7223144 100644 --- a/frontends/monkey/layout.c +++ b/frontends/monkey/layout.c @@ -30,11 +30,11 @@ #include "monkey/layout.h" static nserror nsfont_width(const plot_font_style_t *fstyle, - const char *string, size_t length, - int *width) + const char *string, size_t length, + int *width) { - *width = (fstyle->size * utf8_bounded_length(string, length)) / FONT_SIZE_SCALE; - return NSERROR_OK; + *width = (fstyle->size * utf8_bounded_length(string, length)) / FONT_SIZE_SCALE; + return NSERROR_OK; } /** @@ -50,14 +50,14 @@ static nserror nsfont_width(const plot_font_style_t *fstyle, */ static nserror nsfont_position_in_string(const plot_font_style_t *fstyle, - const char *string, size_t length, - int x, size_t *char_offset, int *actual_x) + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x) { - *char_offset = x / (fstyle->size / FONT_SIZE_SCALE); - if (*char_offset > length) - *char_offset = length; - *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE); - return NSERROR_OK; + *char_offset = x / (fstyle->size / FONT_SIZE_SCALE); + if (*char_offset > length) + *char_offset = length; + *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE); + return NSERROR_OK; } @@ -85,27 +85,27 @@ static nserror nsfont_position_in_string(const plot_font_style_t *fstyle, */ static nserror nsfont_split(const plot_font_style_t *fstyle, - const char *string, size_t length, - int x, size_t *char_offset, int *actual_x) + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x) { - int c_off = *char_offset = x / (fstyle->size / FONT_SIZE_SCALE); - if (*char_offset > length) { - *char_offset = length; - } else { - while (*char_offset > 0) { - if (string[*char_offset] == ' ') - break; - (*char_offset)--; - } - if (*char_offset == 0) { - *char_offset = c_off; - while (*char_offset < length && string[*char_offset] != ' ') { - (*char_offset)++; - } - } - } - *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE); - return NSERROR_OK; + int c_off = *char_offset = x / (fstyle->size / FONT_SIZE_SCALE); + if (*char_offset > length) { + *char_offset = length; + } else { + while (*char_offset > 0) { + if (string[*char_offset] == ' ') + break; + (*char_offset)--; + } + if (*char_offset == 0) { + *char_offset = c_off; + while (*char_offset < length && string[*char_offset] != ' ') { + (*char_offset)++; + } + } + } + *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE); + return NSERROR_OK; } static struct gui_layout_table layout_table = { diff --git a/frontends/monkey/main.c b/frontends/monkey/main.c index 0059ff047..1bea02471 100644 --- a/frontends/monkey/main.c +++ b/frontends/monkey/main.c @@ -66,8 +66,8 @@ static bool monkey_done = false; */ static void die(const char * const error) { - fprintf(stderr, "DIE %s\n", error); - exit(EXIT_FAILURE); + fprintf(stderr, "DIE %s\n", error); + exit(EXIT_FAILURE); } /** obtain language from environment @@ -78,29 +78,29 @@ static void die(const char * const error) */ static const char *get_language(void) { - const char *lang; + const char *lang; - lang = getenv("LANGUAGE"); - if ((lang != NULL) && (lang[0] != '\0')) { - return lang; - } + lang = getenv("LANGUAGE"); + if ((lang != NULL) && (lang[0] != '\0')) { + return lang; + } - lang = getenv("LC_ALL"); - if ((lang != NULL) && (lang[0] != '\0')) { - return lang; - } + lang = getenv("LC_ALL"); + if ((lang != NULL) && (lang[0] != '\0')) { + return lang; + } - lang = getenv("LC_MESSAGES"); - if ((lang != NULL) && (lang[0] != '\0')) { - return lang; - } + lang = getenv("LC_MESSAGES"); + if ((lang != NULL) && (lang[0] != '\0')) { + return lang; + } - lang = getenv("LANG"); - if ((lang != NULL) && (lang[0] != '\0')) { - return lang; - } + lang = getenv("LANG"); + if ((lang != NULL) && (lang[0] != '\0')) { + return lang; + } - return NULL; + return NULL; } @@ -120,92 +120,97 @@ static const char *get_language(void) */ static const char * const *get_languagev(void) { - static const char *langv[LANGV_SIZE]; - int langidx = 0; /* index of next entry in vector */ - static char langs[LANGS_SIZE]; - char *curp; /* next language parameter in langs string */ - const char *lange; /* language from environment variable */ - int lang_len; - char *cln; /* colon in lange */ - - /* return cached vector */ - if (langv[0] != NULL) { - return &langv[0]; - } - - curp = &langs[0]; - - lange = get_language(); - - if (lange != NULL) { - lang_len = strlen(lange) + 1; - if (lang_len < (LANGS_SIZE - 2)) { - memcpy(curp, lange, lang_len); - while ((curp[0] != 0) && - (langidx < (LANGV_SIZE - 2))) { - /* avoid using strchrnul as it is not portable */ - cln = strchr(curp, ':'); - if (cln == NULL) { - langv[langidx++] = curp; - curp += lang_len; - break; - } else { - if ((cln - curp) > 1) { - /* only place non empty entries in vector */ - langv[langidx++] = curp; - } - *cln++ = 0; /* null terminate */ - lang_len -= (cln - curp); - curp = cln; + static const char *langv[LANGV_SIZE]; + int langidx = 0; /* index of next entry in vector */ + static char langs[LANGS_SIZE]; + char *curp; /* next language parameter in langs string */ + const char *lange; /* language from environment variable */ + int lang_len; + char *cln; /* colon in lange */ + + /* return cached vector */ + if (langv[0] != NULL) { + return &langv[0]; } - } - } - } - /* ensure C language is present */ - langv[langidx++] = curp; - *curp++ = 'C'; - *curp++ = 0; - langv[langidx] = NULL; + curp = &langs[0]; + + lange = get_language(); + + if (lange != NULL) { + lang_len = strlen(lange) + 1; + if (lang_len < (LANGS_SIZE - 2)) { + memcpy(curp, lange, lang_len); + while ((curp[0] != 0) && + (langidx < (LANGV_SIZE - 2))) { + /* avoid using strchrnul as it is not portable */ + cln = strchr(curp, ':'); + if (cln == NULL) { + langv[langidx++] = curp; + curp += lang_len; + break; + } else { + if ((cln - curp) > 1) { + /* only place non empty entries in vector */ + langv[langidx++] = curp; + } + *cln++ = 0; /* null terminate */ + lang_len -= (cln - curp); + curp = cln; + } + } + } + } - return &langv[0]; + /* ensure C language is present */ + langv[langidx++] = curp; + *curp++ = 'C'; + *curp++ = 0; + langv[langidx] = NULL; + + return &langv[0]; } /* Stolen from gtk/gui.c */ static char ** nsmonkey_init_resource(const char *resource_path) { - const char * const *langv; - char **pathv; /* resource path string vector */ - char **respath; /* resource paths vector */ + const char * const *langv; + char **pathv; /* resource path string vector */ + char **respath; /* resource paths vector */ - pathv = filepath_path_to_strvec(resource_path); + pathv = filepath_path_to_strvec(resource_path); - langv = get_languagev(); + langv = get_languagev(); - respath = filepath_generate(pathv, langv); + respath = filepath_generate(pathv, langv); - filepath_free_strvec(pathv); + filepath_free_strvec(pathv); - return respath; + return respath; } static void monkey_quit(void) { - urldb_save_cookies(nsoption_charp(cookie_jar)); - urldb_save(nsoption_charp(url_file)); - monkey_fetch_filetype_fin(); + urldb_save_cookies(nsoption_charp(cookie_jar)); + urldb_save(nsoption_charp(url_file)); + monkey_fetch_filetype_fin(); } static nserror gui_launch_url(struct nsurl *url) { - fprintf(stdout, "GENERIC LAUNCH URL %s\n", nsurl_access(url)); - return NSERROR_OK; + fprintf(stdout, "GENERIC LAUNCH URL %s\n", nsurl_access(url)); + return NSERROR_OK; } static void quit_handler(int argc, char **argv) { - monkey_done = true; + monkey_done = true; +} + +static void monkey_options_handle_command(int argc, char **argv) +{ + nsoption_commandline(&argc, argv, nsoptions); } /** @@ -216,12 +221,12 @@ static void quit_handler(int argc, char **argv) */ static nserror set_defaults(struct nsoption_s *defaults) { - /* Set defaults for absent option strings */ - nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies")); - nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies")); - nsoption_setnull_charp(url_file, strdup("~/.netsurf/URLs")); + /* Set defaults for absent option strings */ + nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies")); + nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies")); + nsoption_setnull_charp(url_file, strdup("~/.netsurf/URLs")); - return NSERROR_OK; + return NSERROR_OK; } @@ -230,170 +235,174 @@ static nserror set_defaults(struct nsoption_s *defaults) */ static bool nslog_stream_configure(FILE *fptr) { - /* set log stream to be non-buffering */ - setbuf(fptr, NULL); + /* set log stream to be non-buffering */ + setbuf(fptr, NULL); - return true; + return true; } static struct gui_misc_table monkey_misc_table = { - .schedule = monkey_schedule, - .warning = monkey_warn_user, + .schedule = monkey_schedule, + .warning = monkey_warn_user, - .quit = monkey_quit, - .launch_url = gui_launch_url, - .cert_verify = gui_cert_verify, - .login = gui_401login_open, + .quit = monkey_quit, + .launch_url = gui_launch_url, + .cert_verify = gui_cert_verify, + .login = gui_401login_open, }; static void monkey_run(void) { - fd_set read_fd_set, write_fd_set, exc_fd_set; - int max_fd; - int rdy_fd; - int schedtm; - struct timeval tv; - struct timeval* timeout; - - while (!monkey_done) { - - /* clears fdset */ - fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); - - /* add stdin to the set */ - if (max_fd < 0) { - max_fd = 0; - } - FD_SET(0, &read_fd_set); - FD_SET(0, &exc_fd_set); - - /* discover the next scheduled event time */ - schedtm = monkey_schedule_run(); - - /* setup timeout */ - switch (schedtm) { - case -1: - LOG("Iterate blocking"); - fprintf(stdout, "GENERIC POLL BLOCKING\n"); - timeout = NULL; - break; - - case 0: - LOG("Iterate immediate"); - tv.tv_sec = 0; - tv.tv_usec = 0; - timeout = &tv; - break; - - default: - LOG("Iterate non-blocking"); - fprintf(stdout, "GENERIC POLL TIMED\n"); - tv.tv_sec = schedtm / 1000; /* miliseconds to seconds */ - tv.tv_usec = (schedtm % 1000) * 1000; /* remainder to microseconds */ - timeout = &tv; - break; - } - - rdy_fd = select(max_fd + 1, - &read_fd_set, - &write_fd_set, - &exc_fd_set, - timeout); - if (rdy_fd < 0) { - monkey_done = true; - } else if (rdy_fd > 0) { - if (FD_ISSET(0, &read_fd_set)) { - monkey_process_command(); - } - } - } - + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd; + int rdy_fd; + int schedtm; + struct timeval tv; + struct timeval* timeout; + + while (!monkey_done) { + + /* clears fdset */ + fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); + + /* add stdin to the set */ + if (max_fd < 0) { + max_fd = 0; + } + FD_SET(0, &read_fd_set); + FD_SET(0, &exc_fd_set); + + /* discover the next scheduled event time */ + schedtm = monkey_schedule_run(); + + /* setup timeout */ + switch (schedtm) { + case -1: + LOG("Iterate blocking"); + fprintf(stdout, "GENERIC POLL BLOCKING\n"); + timeout = NULL; + break; + + case 0: + LOG("Iterate immediate"); + tv.tv_sec = 0; + tv.tv_usec = 0; + timeout = &tv; + break; + + default: + LOG("Iterate non-blocking"); + fprintf(stdout, "GENERIC POLL TIMED %d\n", schedtm); + tv.tv_sec = schedtm / 1000; /* miliseconds to seconds */ + tv.tv_usec = (schedtm % 1000) * 1000; /* remainder to microseconds */ + timeout = &tv; + break; + } + + rdy_fd = select(max_fd + 1, + &read_fd_set, + &write_fd_set, + &exc_fd_set, + timeout); + if (rdy_fd < 0) { + monkey_done = true; + } else if (rdy_fd > 0) { + if (FD_ISSET(0, &read_fd_set)) { + monkey_process_command(); + } + } + } } int main(int argc, char **argv) { - char *messages; - char *options; - char buf[PATH_MAX]; - nserror ret; - struct netsurf_table monkey_table = { - .misc = &monkey_misc_table, - .window = monkey_window_table, - .download = monkey_download_table, - .fetch = monkey_fetch_table, - .bitmap = monkey_bitmap_table, - .layout = monkey_layout_table, - }; - - ret = netsurf_register(&monkey_table); - if (ret != NSERROR_OK) { - die("NetSurf operation table failed registration"); - } - - /* Unbuffer stdin/out/err */ - setbuf(stdin, NULL); - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - /* Prep the search paths */ - respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./monkey/res"); - - /* initialise logging. Not fatal if it fails but not much we can do - * about it either. - */ - nslog_init(nslog_stream_configure, &argc, argv); - - /* user options setup */ - ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); - if (ret != NSERROR_OK) { - die("Options failed to initialise"); - } - options = filepath_find(respaths, "Choices"); - nsoption_read(options, nsoptions); - free(options); - nsoption_commandline(&argc, argv, nsoptions); - - messages = filepath_find(respaths, "Messages"); - ret = messages_add_from_file(messages); - if (ret != NSERROR_OK) { - LOG("Messages failed to load"); - } - - /* common initialisation */ - ret = netsurf_init(NULL); - free(messages); - if (ret != NSERROR_OK) { - die("NetSurf failed to initialise"); - } - - filepath_sfinddef(respaths, buf, "mime.types", "/etc/"); - monkey_fetch_filetype_init(buf); - - urldb_load(nsoption_charp(url_file)); - urldb_load_cookies(nsoption_charp(cookie_file)); - - ret = monkey_register_handler("QUIT", quit_handler); - if (ret != NSERROR_OK) { - die("quit handler failed to register"); - } - - ret = monkey_register_handler("WINDOW", monkey_window_handle_command); - if (ret != NSERROR_OK) { - die("window handler fialed to register"); - } - - fprintf(stdout, "GENERIC STARTED\n"); - monkey_run(); - - fprintf(stdout, "GENERIC CLOSING_DOWN\n"); - monkey_kill_browser_windows(); - - netsurf_exit(); - fprintf(stdout, "GENERIC FINISHED\n"); - - /* finalise options */ - nsoption_finalise(nsoptions, nsoptions_default); - - return 0; + char *messages; + char *options; + char buf[PATH_MAX]; + nserror ret; + struct netsurf_table monkey_table = { + .misc = &monkey_misc_table, + .window = monkey_window_table, + .download = monkey_download_table, + .fetch = monkey_fetch_table, + .bitmap = monkey_bitmap_table, + .layout = monkey_layout_table, + }; + + ret = netsurf_register(&monkey_table); + if (ret != NSERROR_OK) { + die("NetSurf operation table failed registration"); + } + + /* Unbuffer stdin/out/err */ + setbuf(stdin, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + /* Prep the search paths */ + respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./frontends/monkey/res"); + + /* initialise logging. Not fatal if it fails but not much we can do + * about it either. + */ + nslog_init(nslog_stream_configure, &argc, argv); + + /* user options setup */ + ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); + if (ret != NSERROR_OK) { + die("Options failed to initialise"); + } + options = filepath_find(respaths, "Choices"); + nsoption_read(options, nsoptions); + free(options); + nsoption_commandline(&argc, argv, nsoptions); + + messages = filepath_find(respaths, "Messages"); + ret = messages_add_from_file(messages); + if (ret != NSERROR_OK) { + LOG("Messages failed to load"); + } + + /* common initialisation */ + ret = netsurf_init(NULL); + free(messages); + if (ret != NSERROR_OK) { + die("NetSurf failed to initialise"); + } + + filepath_sfinddef(respaths, buf, "mime.types", "/etc/"); + monkey_fetch_filetype_init(buf); + + urldb_load(nsoption_charp(url_file)); + urldb_load_cookies(nsoption_charp(cookie_file)); + + ret = monkey_register_handler("QUIT", quit_handler); + if (ret != NSERROR_OK) { + die("quit handler failed to register"); + } + + ret = monkey_register_handler("WINDOW", monkey_window_handle_command); + if (ret != NSERROR_OK) { + die("window handler failed to register"); + } + + ret = monkey_register_handler("OPTIONS", monkey_options_handle_command); + if (ret != NSERROR_OK) { + die("options handler failed to register"); + } + + fprintf(stdout, "GENERIC STARTED\n"); + monkey_run(); + + fprintf(stdout, "GENERIC CLOSING_DOWN\n"); + monkey_kill_browser_windows(); + + netsurf_exit(); + fprintf(stdout, "GENERIC FINISHED\n"); + + /* finalise options */ + nsoption_finalise(nsoptions, nsoptions_default); + + return 0; } diff --git a/frontends/monkey/plot.c b/frontends/monkey/plot.c index 7ed2205ca..d00dca754 100644 --- a/frontends/monkey/plot.c +++ b/frontends/monkey/plot.c @@ -58,8 +58,8 @@ monkey_plot_clip(const struct redraw_context *ctx, const struct rect *clip) */ static nserror monkey_plot_arc(const struct redraw_context *ctx, - const plot_style_t *style, - int x, int y, int radius, int angle1, int angle2) + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { fprintf(stdout, "PLOT ARC X %d Y %d RADIUS %d ANGLE1 %d ANGLE2 %d\n", @@ -82,8 +82,8 @@ monkey_plot_arc(const struct redraw_context *ctx, */ static nserror monkey_plot_disc(const struct redraw_context *ctx, - const plot_style_t *style, - int x, int y, int radius) + const plot_style_t *style, + int x, int y, int radius) { fprintf(stdout, "PLOT DISC X %d Y %d RADIUS %d\n", @@ -105,8 +105,8 @@ monkey_plot_disc(const struct redraw_context *ctx, */ static nserror monkey_plot_line(const struct redraw_context *ctx, - const plot_style_t *style, - const struct rect *line) + const plot_style_t *style, + const struct rect *line) { fprintf(stdout, "PLOT LINE X0 %d Y0 %d X1 %d Y1 %d\n", @@ -130,8 +130,8 @@ monkey_plot_line(const struct redraw_context *ctx, */ static nserror monkey_plot_rectangle(const struct redraw_context *ctx, - const plot_style_t *style, - const struct rect *rect) + const plot_style_t *style, + const struct rect *rect) { fprintf(stdout, "PLOT RECT X0 %d Y0 %d X1 %d Y1 %d\n", @@ -156,9 +156,9 @@ monkey_plot_rectangle(const struct redraw_context *ctx, */ static nserror monkey_plot_polygon(const struct redraw_context *ctx, - const plot_style_t *style, - const int *p, - unsigned int n) + const plot_style_t *style, + const int *p, + unsigned int n) { fprintf(stdout, "PLOT POLYGON VERTICIES %d\n", @@ -183,11 +183,11 @@ monkey_plot_polygon(const struct redraw_context *ctx, */ static nserror monkey_plot_path(const struct redraw_context *ctx, - const plot_style_t *pstyle, - const float *p, - unsigned int n, - float width, - const float transform[6]) + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { fprintf(stdout, "PLOT PATH VERTICIES %d WIDTH %f\n", @@ -222,12 +222,12 @@ monkey_plot_path(const struct redraw_context *ctx, */ static nserror monkey_plot_bitmap(const struct redraw_context *ctx, - struct bitmap *bitmap, - int x, int y, - int width, - int height, - colour bg, - bitmap_flags_t flags) + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { fprintf(stdout, "PLOT BITMAP X %d Y %d WIDTH %d HEIGHT %d\n", @@ -249,11 +249,11 @@ monkey_plot_bitmap(const struct redraw_context *ctx, */ static nserror monkey_plot_text(const struct redraw_context *ctx, - const struct plot_font_style *fstyle, - int x, - int y, - const char *text, - size_t length) + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { fprintf(stdout, "PLOT TEXT X %d Y %d STR %*s\n", diff --git a/frontends/monkey/schedule.c b/frontends/monkey/schedule.c index 8c638c0b9..af1144a0e 100644 --- a/frontends/monkey/schedule.c +++ b/frontends/monkey/schedule.c @@ -38,10 +38,10 @@ static struct nscallback *schedule_list = NULL; */ struct nscallback { - struct nscallback *next; - struct timeval tv; - void (*callback)(void *p); - void *p; + struct nscallback *next; + struct timeval tv; + void (*callback)(void *p); + void *p; }; /** @@ -54,170 +54,163 @@ struct nscallback */ static nserror schedule_remove(void (*callback)(void *p), void *p) { - struct nscallback *cur_nscb; - struct nscallback *prev_nscb; - struct nscallback *unlnk_nscb; - - /* check there is something on the list to remove */ - if (schedule_list == NULL) { - return NSERROR_OK; - } - - SRLOG("removing %p, %p", callback, p); - - cur_nscb = schedule_list; - prev_nscb = NULL; - - while (cur_nscb != NULL) { - if ((cur_nscb->callback == callback) && - (cur_nscb->p == p)) { - /* item to remove */ - - SRLOG("callback entry %p removing %p(%p)", - cur_nscb, cur_nscb->callback, cur_nscb->p); - - /* remove callback */ - unlnk_nscb = cur_nscb; - cur_nscb = unlnk_nscb->next; - - if (prev_nscb == NULL) { - schedule_list = cur_nscb; - } else { - prev_nscb->next = cur_nscb; - } - free (unlnk_nscb); - } else { - /* move to next element */ - prev_nscb = cur_nscb; - cur_nscb = prev_nscb->next; - } - } - - return NSERROR_OK; + struct nscallback *cur_nscb; + struct nscallback *prev_nscb; + struct nscallback *unlnk_nscb; + + /* check there is something on the list to remove */ + if (schedule_list == NULL) { + return NSERROR_OK; + } + + SRLOG("removing %p, %p", callback, p); + + cur_nscb = schedule_list; + prev_nscb = NULL; + + while (cur_nscb != NULL) { + if ((cur_nscb->callback == callback) && + (cur_nscb->p == p)) { + /* item to remove */ + + SRLOG("callback entry %p removing %p(%p)", + cur_nscb, cur_nscb->callback, cur_nscb->p); + + /* remove callback */ + unlnk_nscb = cur_nscb; + cur_nscb = unlnk_nscb->next; + + if (prev_nscb == NULL) { + schedule_list = cur_nscb; + } else { + prev_nscb->next = cur_nscb; + } + free (unlnk_nscb); + } else { + /* move to next element */ + prev_nscb = cur_nscb; + cur_nscb = prev_nscb->next; + } + } + + return NSERROR_OK; } -/* exported function documented in framebuffer/schedule.h */ +/* exported function documented in monkey/schedule.h */ nserror monkey_schedule(int tival, void (*callback)(void *p), void *p) { - struct nscallback *nscb; - struct timeval tv; - nserror ret; + struct nscallback *nscb; + struct timeval tv; + nserror ret; - /* ensure uniqueness of the callback and context */ - ret = schedule_remove(callback, p); - if ((tival < 0) || (ret != NSERROR_OK)) { - return ret; - } + /* ensure uniqueness of the callback and context */ + ret = schedule_remove(callback, p); + if ((tival < 0) || (ret != NSERROR_OK)) { + return ret; + } - SRLOG("Adding %p(%p) in %d", callback, p, tival); + SRLOG("Adding %p(%p) in %d", callback, p, tival); - tv.tv_sec = tival / 1000; /* miliseconds to seconds */ - tv.tv_usec = (tival % 1000) * 1000; /* remainder to microseconds */ + tv.tv_sec = tival / 1000; /* miliseconds to seconds */ + tv.tv_usec = (tival % 1000) * 1000; /* remainder to microseconds */ - nscb = calloc(1, sizeof(struct nscallback)); + nscb = calloc(1, sizeof(struct nscallback)); - gettimeofday(&nscb->tv, NULL); - timeradd(&nscb->tv, &tv, &nscb->tv); + gettimeofday(&nscb->tv, NULL); + timeradd(&nscb->tv, &tv, &nscb->tv); - nscb->callback = callback; - nscb->p = p; + nscb->callback = callback; + nscb->p = p; - /* add to list front */ - nscb->next = schedule_list; - schedule_list = nscb; + /* add to list front */ + nscb->next = schedule_list; + schedule_list = nscb; - return NSERROR_OK; + return NSERROR_OK; } -/* exported function documented in framebuffer/schedule.h */ +/* exported function documented in monkey/schedule.h */ int monkey_schedule_run(void) { - struct timeval tv; - struct timeval nexttime; - struct timeval rettime; - struct nscallback *cur_nscb; - struct nscallback *prev_nscb; - struct nscallback *unlnk_nscb; - - if (schedule_list == NULL) - return -1; - - /* reset enumeration to the start of the list */ - cur_nscb = schedule_list; - prev_nscb = NULL; - nexttime = cur_nscb->tv; - - gettimeofday(&tv, NULL); - - while (cur_nscb != NULL) { - if (timercmp(&tv, &cur_nscb->tv, >)) { - /* scheduled time */ - - /* remove callback */ - unlnk_nscb = cur_nscb; - - if (prev_nscb == NULL) { - schedule_list = unlnk_nscb->next; - } else { - prev_nscb->next = unlnk_nscb->next; - } - - unlnk_nscb->callback(unlnk_nscb->p); - - free(unlnk_nscb); - - /* need to deal with callback modifying the list. */ - if (schedule_list == NULL) - return -1; /* no more callbacks scheduled */ - - /* reset enumeration to the start of the list */ - cur_nscb = schedule_list; - prev_nscb = NULL; - nexttime = cur_nscb->tv; - } else { - /* if the time to the event is sooner than the - * currently recorded soonest event record it - */ - if (timercmp(&nexttime, &cur_nscb->tv, >)) { + struct timeval tv; + struct timeval nexttime; + struct timeval rettime; + struct nscallback *cur_nscb; + struct nscallback *prev_nscb; + struct nscallback *unlnk_nscb; + + if (schedule_list == NULL) + return -1; + + /* reset enumeration to the start of the list */ + cur_nscb = schedule_list; + prev_nscb = NULL; nexttime = cur_nscb->tv; - } - /* move to next element */ - prev_nscb = cur_nscb; - cur_nscb = prev_nscb->next; - } - } - /* make rettime relative to now */ - timersub(&nexttime, &tv, &rettime); - - SRLOG("returning time to next event as %ldms", - (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000)); - - /* return next event time in milliseconds (24days max wait) */ - return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000); + gettimeofday(&tv, NULL); + + while (cur_nscb != NULL) { + if (timercmp(&tv, &cur_nscb->tv, >)) { + /* scheduled time */ + + /* remove callback */ + unlnk_nscb = cur_nscb; + + if (prev_nscb == NULL) { + schedule_list = unlnk_nscb->next; + } else { + prev_nscb->next = unlnk_nscb->next; + } + + unlnk_nscb->callback(unlnk_nscb->p); + + free(unlnk_nscb); + + /* need to deal with callback modifying the list. */ + if (schedule_list == NULL) + return -1; /* no more callbacks scheduled */ + + /* reset enumeration to the start of the list */ + cur_nscb = schedule_list; + prev_nscb = NULL; + nexttime = cur_nscb->tv; + } else { + /* if the time to the event is sooner than the + * currently recorded soonest event record it + */ + if (timercmp(&nexttime, &cur_nscb->tv, >)) { + nexttime = cur_nscb->tv; + } + /* move to next element */ + prev_nscb = cur_nscb; + cur_nscb = prev_nscb->next; + } + } + + /* make rettime relative to now */ + timersub(&nexttime, &tv, &rettime); + + SRLOG("returning time to next event as %ldms", + (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000)); + + /* return next event time in milliseconds (24days max wait) */ + return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000); } void monkey_schedule_list(void) { - struct timeval tv; - struct nscallback *cur_nscb; + struct timeval tv; + struct nscallback *cur_nscb; - gettimeofday(&tv, NULL); + gettimeofday(&tv, NULL); - LOG("schedule list at %lld:%ld", (long long)tv.tv_sec, tv.tv_usec); + LOG("schedule list at %lld:%ld", (long long)tv.tv_sec, tv.tv_usec); - cur_nscb = schedule_list; + cur_nscb = schedule_list; - while (cur_nscb != NULL) { - LOG("Schedule %p at %lld:%ld", - cur_nscb, (long long)cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec); - cur_nscb = cur_nscb->next; - } + while (cur_nscb != NULL) { + LOG("Schedule %p at %lld:%ld", + cur_nscb, (long long)cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec); + cur_nscb = cur_nscb->next; + } } - - -/* - * Local Variables: - * c-basic-offset:2 - * End: - */ diff --git a/frontends/riscos/cookies.c b/frontends/riscos/cookies.c index 38963ab3a..614bc3d10 100644 --- a/frontends/riscos/cookies.c +++ b/frontends/riscos/cookies.c @@ -377,7 +377,7 @@ static nserror ro_cookie_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct ro_cookie_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c index a885977a8..77dd1c375 100644 --- a/frontends/riscos/corewindow.c +++ b/frontends/riscos/corewindow.c @@ -42,6 +42,7 @@ #include "riscos/wimp_event.h" #include "riscos/dialog.h" #include "riscos/gui.h" +#include "riscos/window.h" #include "riscos/toolbar.h" #include "riscos/mouse.h" #include "riscos/corewindow.h" diff --git a/frontends/riscos/dialog.c b/frontends/riscos/dialog.c index 7a0197cde..6414778db 100644 --- a/frontends/riscos/dialog.c +++ b/frontends/riscos/dialog.c @@ -47,6 +47,7 @@ #include "riscos/local_history.h" #include "riscos/global_history.h" #include "riscos/gui.h" +#include "riscos/window.h" #include "riscos/hotlist.h" #include "riscos/menus.h" #include "riscos/save.h" diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c index 94e1d4a03..d122a4d7f 100644 --- a/frontends/riscos/global_history.c +++ b/frontends/riscos/global_history.c @@ -405,7 +405,7 @@ static nserror ro_global_history_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct ro_global_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h index 35be4e1d0..49a8ba417 100644 --- a/frontends/riscos/gui.h +++ b/frontends/riscos/gui.h @@ -139,35 +139,6 @@ void ro_gui_401login_init(void); void gui_401login_open(struct nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw); -/* in window.c */ -void ro_gui_window_set_scale(struct gui_window *g, float scale); -bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message); -void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data); -void ro_gui_window_iconise(struct gui_window *g, - wimp_full_message_window_info *wi); -bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message); -void ro_gui_window_redraw_all(void); -void ro_gui_window_update_boxes(void); -void ro_gui_window_quit(void); -/* void ro_gui_window_close_all(void); */ -#define ro_gui_window_close_all ro_gui_window_quit /* no need for a separate fn */ -void ro_gui_throb(void); -void ro_gui_window_default_options(struct gui_window *gui); -struct gui_window *ro_gui_window_lookup(wimp_w window); -struct gui_window *ro_gui_toolbar_lookup(wimp_w window); -bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, - os_coord *pos); -bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, - os_coord *pos); -enum browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, - wimp_icon_flags type); -enum browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons, - wimp_icon_flags type); -bool ro_gui_shift_pressed(void); -bool ro_gui_ctrl_pressed(void); -bool ro_gui_alt_pressed(void); -void gui_window_set_pointer(struct gui_window *g, enum gui_pointer_shape shape); - /* in schedule.c */ extern bool sched_active; extern os_t sched_time; diff --git a/frontends/riscos/hotlist.c b/frontends/riscos/hotlist.c index d3480093e..b055d1bec 100644 --- a/frontends/riscos/hotlist.c +++ b/frontends/riscos/hotlist.c @@ -466,7 +466,7 @@ static nserror ro_hotlist_init(void) return NSERROR_OK; } - ncwin = malloc(sizeof(struct ro_hotlist_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/riscos/local_history.c b/frontends/riscos/local_history.c index fae78e6ff..f9f1f2e01 100644 --- a/frontends/riscos/local_history.c +++ b/frontends/riscos/local_history.c @@ -28,6 +28,7 @@ #include "utils/nsoption.h" #include "utils/messages.h" #include "utils/log.h" +#include "utils/nsurl.h" #include "netsurf/window.h" #include "netsurf/plotters.h" #include "netsurf/keypress.h" @@ -90,7 +91,7 @@ ro_local_history_draw(struct ro_corewindow *ro_cw, ro_plot_origin_x = originx; ro_plot_origin_y = originy; no_font_blending = true; - local_history_redraw(lhw->session, r->x0, r->y0, r, &ctx); + local_history_redraw(lhw->session, 0, 0, r, &ctx); no_font_blending = false; return NSERROR_OK; @@ -127,7 +128,7 @@ static nserror ro_local_history_tooltip(struct ro_local_history_window *lhw, int x, int y) { int width; - const char *url; + nsurl *url; wimp_window_state state; wimp_icon_state ic; os_box box = {0, 0, 0, 0}; @@ -162,17 +163,19 @@ ro_local_history_tooltip(struct ro_local_history_window *lhw, int x, int y) } /* get width of string */ - error = xwimptextop_string_width(url, - strlen(url) > 256 ? 256 : strlen(url), + error = xwimptextop_string_width(nsurl_access(url), + nsurl_length(url) > 256 ? 256 : nsurl_length(url), &width); if (error) { LOG("xwimptextop_string_width: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); + nsurl_unref(url); return NSERROR_NOMEM; } - ro_gui_set_icon_string(dialog_tooltip, 0, url, true); + ro_gui_set_icon_string(dialog_tooltip, 0, nsurl_access(url), true); + nsurl_unref(url); /* resize icon appropriately */ ic.w = dialog_tooltip; @@ -296,7 +299,7 @@ ro_local_history_init(struct browser_window *bw, return res; } - ncwin = malloc(sizeof(struct ro_local_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/riscos/save.c b/frontends/riscos/save.c index 37474b85c..bed0f5dd1 100644 --- a/frontends/riscos/save.c +++ b/frontends/riscos/save.c @@ -56,6 +56,7 @@ #include "riscos/bitmap.h" #include "riscos/dialog.h" #include "riscos/gui.h" +#include "riscos/window.h" #include "riscos/menus.h" #include "riscos/message.h" #include "riscos/mouse.h" diff --git a/frontends/riscos/textselection.c b/frontends/riscos/textselection.c index bce35750f..5a430c06f 100644 --- a/frontends/riscos/textselection.c +++ b/frontends/riscos/textselection.c @@ -36,6 +36,7 @@ #include "netsurf/browser_window.h" #include "riscos/gui.h" +#include "riscos/window.h" #include "riscos/menus.h" #include "riscos/message.h" #include "riscos/mouse.h" diff --git a/frontends/riscos/url_complete.c b/frontends/riscos/url_complete.c index 3ca9be4c0..16c6e3a2e 100644 --- a/frontends/riscos/url_complete.c +++ b/frontends/riscos/url_complete.c @@ -36,6 +36,7 @@ #include "riscos/global_history.h" #include "riscos/gui.h" +#include "riscos/window.h" #include "riscos/mouse.h" #include "riscos/toolbar.h" #include "riscos/url_complete.h" diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c index de0fcab2b..6dbcc325b 100644 --- a/frontends/riscos/window.c +++ b/frontends/riscos/window.c @@ -35,6 +35,7 @@ #include <stdint.h> #include <time.h> #include <string.h> +#include <limits.h> #include <oslib/colourtrans.h> #include <oslib/osbyte.h> #include <oslib/osfile.h> @@ -63,7 +64,6 @@ #include "netsurf/keypress.h" #include "desktop/browser_history.h" #include "desktop/cookie_manager.h" -#include "desktop/scrollbar.h" #include "riscos/bitmap.h" #include "riscos/buffer.h" @@ -91,70 +91,6 @@ #include "riscos/ucstables.h" #include "riscos/filetype.h" -static void gui_window_set_extent(struct gui_window *g, int width, int height); - -static void ro_gui_window_redraw(wimp_draw *redraw); -static void ro_gui_window_scroll(wimp_scroll *scroll); -static void ro_gui_window_pointer_entering(wimp_entering *entering); -static void ro_gui_window_track_end(wimp_leaving *leaving, void *data); -static void ro_gui_window_open(wimp_open *open); -static void ro_gui_window_close(wimp_w w); -static bool ro_gui_window_click(wimp_pointer *mouse); -static bool ro_gui_window_keypress(wimp_key *key); -static bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key); -static bool ro_gui_window_handle_local_keypress(struct gui_window *g, - wimp_key *key, bool is_toolbar); -static bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_pointer *pointer); -static void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action); -static bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action); -static void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu); - -static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data); - -static void ro_gui_window_scroll_action(struct gui_window *g, - int scroll_x, int scroll_y); - -static void ro_gui_window_toolbar_click(void *data, - toolbar_action_type action_type, union toolbar_action action); - -static bool ro_gui_window_content_export_types(struct hlcache_handle *h, - bool *export_draw, bool *export_sprite); -static void ro_gui_window_prepare_pageinfo(struct gui_window *g); -static void ro_gui_window_prepare_objectinfo(struct hlcache_handle *object, - nsurl *target_url); - -static void ro_gui_window_launch_url(struct gui_window *g, const char *url); -static void ro_gui_window_action_home(struct gui_window *g); -static void ro_gui_window_action_new_window(struct gui_window *g); -static void ro_gui_window_action_local_history(struct gui_window *g); -static void ro_gui_window_action_save(struct gui_window *g, - gui_save_type save_type); -static void ro_gui_window_action_search(struct gui_window *g); -static void ro_gui_window_action_zoom(struct gui_window *g); -static void ro_gui_window_action_add_bookmark(struct gui_window *g); -static void ro_gui_window_action_remove_bookmark(struct gui_window *g); -static void ro_gui_window_action_print(struct gui_window *g); -static void ro_gui_window_action_page_info(struct gui_window *g); - -static void ro_gui_window_remove_update_boxes(struct gui_window *g); -static void ro_gui_window_update_toolbar_buttons(struct gui_window *g); -static void ro_gui_window_update_toolbar(void *data); -static void ro_gui_window_save_toolbar_buttons(void *data, char *config); -static void ro_gui_window_update_theme(void *data, bool ok); - -static bool ro_gui_window_import_text(struct gui_window *g, - const char *filename); -static void ro_gui_window_clone_options( - struct gui_window *new_gui, - struct gui_window *old_gui); - -static bool ro_gui_window_prepare_form_select_menu(struct gui_window *bw, - struct form_control *control); -static void ro_gui_window_process_form_select_menu(struct gui_window *g, - wimp_selection *selection); #ifndef wimp_KEY_END #define wimp_KEY_END wimp_KEY_COPY @@ -167,6 +103,11 @@ static void ro_gui_window_process_form_select_menu(struct gui_window *g, #define SCROLL_VISIBLE_PADDING 32 +#define SCROLL_TOP INT_MIN +#define SCROLL_PAGE_UP (INT_MIN + 1) +#define SCROLL_PAGE_DOWN (INT_MAX - 1) +#define SCROLL_BOTTOM INT_MAX + /** Remembers which iconised sprite numbers are in use */ static bool iconise_used[64]; static int iconise_next = 0; @@ -205,7 +146,8 @@ struct ro_gui_pointer_entry { int yactive; }; -/** Map from gui_pointer_shape to pointer sprite data. Must be ordered as +/** + * Map from gui_pointer_shape to pointer sprite data. Must be ordered as * enum gui_pointer_shape. */ struct ro_gui_pointer_entry ro_gui_pointer_table[] = { { true, "ptr_default", 0, 0 }, @@ -242,143 +184,22 @@ struct update_box { struct update_box *pending_updates; #define MARGIN 4 -static const struct toolbar_callbacks ro_gui_window_toolbar_callbacks = { - ro_gui_window_update_theme, - ro_gui_window_update_toolbar, - (void (*)(void *)) ro_gui_window_update_toolbar_buttons, - ro_gui_window_toolbar_click, - ro_gui_window_toolbar_keypress, - ro_gui_window_save_toolbar_buttons -}; - - -/** - * Initialise the browser window module and its menus. - */ - -void ro_gui_window_initialise(void) -{ - /* Build the browser window menu. */ - - static const struct ns_menu browser_definition = { - "NetSurf", { - { "Page", BROWSER_PAGE, 0 }, - { "Page.PageInfo",BROWSER_PAGE_INFO, &dialog_pageinfo }, - { "Page.Save", BROWSER_SAVE, &dialog_saveas }, - { "Page.SaveComp", BROWSER_SAVE_COMPLETE, &dialog_saveas }, - { "Page.Export", NO_ACTION, 0 }, -#ifdef WITH_DRAW_EXPORT - { "Page.Export.Draw", BROWSER_EXPORT_DRAW, &dialog_saveas }, -#endif -#ifdef WITH_PDF_EXPORT - { "Page.Export.PDF", BROWSER_EXPORT_PDF, &dialog_saveas }, -#endif - { "Page.Export.Text", BROWSER_EXPORT_TEXT, &dialog_saveas }, - { "Page.SaveURL", NO_ACTION, 0 }, - { "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, &dialog_saveas }, - { "Page.SaveURL.URL", BROWSER_SAVE_URL_URL, &dialog_saveas }, - { "Page.SaveURL.LinkText", BROWSER_SAVE_URL_TEXT, &dialog_saveas }, - { "_Page.Print", BROWSER_PRINT, &dialog_print }, - { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 }, - { "Page.FindText", BROWSER_FIND_TEXT, &dialog_search }, - { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 }, - { "Object", BROWSER_OBJECT, 0 }, - { "Object.Object", BROWSER_OBJECT_OBJECT, 0 }, - { "Object.Object.ObjInfo", BROWSER_OBJECT_INFO, &dialog_objinfo }, - { "Object.Object.ObjSave", BROWSER_OBJECT_SAVE, &dialog_saveas }, - { "Object.Object.Export", BROWSER_OBJECT_EXPORT, 0 }, - { "Object.Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, &dialog_saveas }, -#ifdef WITH_DRAW_EXPORT - { "Object.Object.Export.ObjDraw", BROWSER_OBJECT_EXPORT_DRAW, &dialog_saveas }, -#endif - { "Object.Object.SaveURL", NO_ACTION, 0 }, - { "Object.Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, &dialog_saveas }, - { "Object.Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, &dialog_saveas }, - { "Object.Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, &dialog_saveas }, - { "Object.Object.ObjPrint", BROWSER_OBJECT_PRINT, 0 }, - { "Object.Object.ObjReload", BROWSER_OBJECT_RELOAD, 0 }, - { "Object.Link", BROWSER_OBJECT_LINK, 0 }, - { "Object.Link.LinkSave", BROWSER_LINK_SAVE, 0 }, - { "Object.Link.LinkSave.URI", BROWSER_LINK_SAVE_URI, &dialog_saveas }, - { "Object.Link.LinkSave.URL", BROWSER_LINK_SAVE_URL, &dialog_saveas }, - { "Object.Link.LinkSave.LinkText", BROWSER_LINK_SAVE_TEXT, &dialog_saveas }, - { "_Object.Link.LinkDload", BROWSER_LINK_DOWNLOAD, 0 }, - { "Object.Link.LinkNew", BROWSER_LINK_NEW_WINDOW, 0 }, - { "Selection", BROWSER_SELECTION, 0 }, - { "_Selection.SelSave", BROWSER_SELECTION_SAVE, &dialog_saveas }, - { "Selection.Copy", BROWSER_SELECTION_COPY, 0 }, - { "Selection.Cut", BROWSER_SELECTION_CUT, 0 }, - { "_Selection.Paste", BROWSER_SELECTION_PASTE, 0 }, - { "Selection.Clear", BROWSER_SELECTION_CLEAR, 0 }, - { "Selection.SelectAll", BROWSER_SELECTION_ALL, 0 }, - { "Navigate", NO_ACTION, 0 }, - { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 }, - { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 }, - { "Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 }, - { "_Navigate.UpLevel", BROWSER_NAVIGATE_UP, 0 }, - { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 }, - { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 }, - { "View", NO_ACTION, 0 }, - { "View.ScaleView", BROWSER_SCALE_VIEW, &dialog_zoom }, - { "View.Images", NO_ACTION, 0 }, - { "View.Images.ForeImg", BROWSER_IMAGES_FOREGROUND, 0 }, - { "View.Images.BackImg", BROWSER_IMAGES_BACKGROUND, 0 }, - { "View.Toolbars", NO_ACTION, 0 }, - { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, - { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 }, - { "_View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 }, - { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, - { "_View.Render", NO_ACTION, 0 }, - { "View.Render.RenderAnims", BROWSER_BUFFER_ANIMS, 0 }, - { "View.Render.RenderAll", BROWSER_BUFFER_ALL, 0 }, - { "_View.OptDefault", BROWSER_SAVE_VIEW, 0 }, - { "View.Window", NO_ACTION, 0 }, - { "View.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 }, - { "View.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 }, - { "_View.Window.WindowSize", BROWSER_WINDOW_COPY, 0 }, - { "View.Window.WindowReset", BROWSER_WINDOW_RESET, 0 }, - { "Utilities", NO_ACTION, 0 }, - { "Utilities.Hotlist", HOTLIST_SHOW, 0 }, - { "Utilities.Hotlist.HotlistAdd", HOTLIST_ADD_URL, 0 }, - { "Utilities.Hotlist.HotlistShow", HOTLIST_SHOW, 0 }, - { "Utilities.History", HISTORY_SHOW_GLOBAL, 0 }, - { "Utilities.History.HistLocal", HISTORY_SHOW_LOCAL, 0 }, - { "Utilities.History.HistGlobal", HISTORY_SHOW_GLOBAL, 0 }, - { "Utilities.Cookies", COOKIES_SHOW, 0 }, - { "Utilities.Cookies.ShowCookies", COOKIES_SHOW, 0 }, - { "Utilities.Cookies.DeleteCookies", COOKIES_DELETE, 0 }, - { "Help", HELP_OPEN_CONTENTS, 0 }, - { "Help.HelpContent", HELP_OPEN_CONTENTS, 0 }, - { "Help.HelpGuide", HELP_OPEN_GUIDE, 0 }, - { "_Help.HelpInfo", HELP_OPEN_INFORMATION, 0 }, - { "Help.HelpCredits", HELP_OPEN_CREDITS, 0 }, - { "_Help.HelpLicence", HELP_OPEN_LICENCE, 0 }, - { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 }, - {NULL, 0, 0} - } - }; - ro_gui_browser_window_menu = - ro_gui_menu_define_menu(&browser_definition); - -} - - -/* - * Interface With Core - */ /** * Place the caret in a browser window. * - * \param g window with caret - * \param x coordinates of caret - * \param y coordinates of caret - * \param height height of caret - * \param clip clip rectangle, or NULL if none + * \param g window with caret + * \param x coordinates of caret + * \param y coordinates of caret + * \param height height of caret + * \param clip clip rectangle, or NULL if none */ - -static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, - const struct rect *clip) +static void +gui_window_place_caret(struct gui_window *g, + int x, + int y, + int height, + const struct rect *clip) { os_error *error; @@ -390,552 +211,229 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh } } + /** - * Create and open a new browser window. + * Updates a windows extent. * - * \param bw bw to create gui_window for - * \param existing an existing gui_window, may be NULL - * \param flags flags for gui window creation - * \return gui window, or NULL on error + * \param g the gui_window to update + * \param width the minimum width, or -1 to use window width + * \param height the minimum height, or -1 to use window height */ - -static struct gui_window *gui_window_create(struct browser_window *bw, - struct gui_window *existing, - gui_window_create_flags flags) +static void gui_window_set_extent(struct gui_window *g, int width, int height) { - int screen_width, screen_height; - static int window_count = 2; - wimp_window window; + int screen_width; + int toolbar_height = 0; wimp_window_state state; os_error *error; - bool open_centred = true; - struct gui_window *g; - g = malloc(sizeof *g); - if (!g) { - ro_warn_user("NoMemory", 0); - return 0; + if (g->toolbar) { + toolbar_height = ro_toolbar_full_height(g->toolbar); } - g->bw = bw; - g->toolbar = 0; - g->status_bar = 0; - g->old_width = 0; - g->old_height = 0; - g->update_extent = true; - g->active = false; - strcpy(g->title, "NetSurf"); - g->iconise_icon = -1; - g->scale = browser_window_get_scale(bw); - /* Set the window position */ - if (existing != NULL && - flags & GW_CREATE_CLONE && - nsoption_bool(window_size_clone)) { - state.w = existing->window; + /* get the current state */ + if ((height == -1) || (width == -1)) { + state.w = g->window; error = xwimp_get_window_state(&state); if (error) { LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); + return; } - window.visible.x0 = state.visible.x0; - window.visible.x1 = state.visible.x1; - window.visible.y0 = state.visible.y0 - 48; - window.visible.y1 = state.visible.y1 - 48; - open_centred = false; - } else { - int win_width, win_height; - ro_gui_screen_size(&screen_width, &screen_height); - - /* Check if we have a preferred position */ - if ((nsoption_int(window_screen_width) != 0) && - (nsoption_int(window_screen_height) != 0)) { - win_width = (nsoption_int(window_width) * - screen_width) / - nsoption_int(window_screen_width); - win_height = (nsoption_int(window_height) * - screen_height) / - nsoption_int(window_screen_height); - window.visible.x0 = (nsoption_int(window_x) * - screen_width) / - nsoption_int(window_screen_width); - window.visible.y0 = (nsoption_int(window_y) * - screen_height) / - nsoption_int(window_screen_height); - if (nsoption_bool(window_stagger)) { - window.visible.y0 += 96 - - (48 * (window_count % 5)); - } - open_centred = false; - if (win_width < 100) - win_width = 100; - if (win_height < 100) - win_height = 100; - } else { - - /* Base how we define the window height/width - on the compile time options set */ - win_width = screen_width * 3 / 4; - if (1600 < win_width) - win_width = 1600; - win_height = win_width * 3 / 4; - - window.visible.x0 = (screen_width - win_width) / 2; - window.visible.y0 = ((screen_height - win_height) / 2) + - 96 - (48 * (window_count % 5)); + if (width == -1) + width = state.visible.x1 - state.visible.x0; + if (height == -1) { + height = state.visible.y1 - state.visible.y0; + height -= toolbar_height; } - window.visible.x1 = window.visible.x0 + win_width; - window.visible.y1 = window.visible.y0 + win_height; } - /* General flags for a non-movable, non-resizable, no-title bar window */ - window.xscroll = 0; - window.yscroll = 0; - window.next = wimp_TOP; - window.flags = wimp_WINDOW_MOVEABLE | - wimp_WINDOW_NEW_FORMAT | - wimp_WINDOW_VSCROLL | - wimp_WINDOW_HSCROLL | - wimp_WINDOW_IGNORE_XEXTENT | - wimp_WINDOW_IGNORE_YEXTENT | - wimp_WINDOW_SCROLL_REPEAT; - window.title_fg = wimp_COLOUR_BLACK; - window.title_bg = wimp_COLOUR_LIGHT_GREY; - window.work_fg = wimp_COLOUR_LIGHT_GREY; - window.work_bg = wimp_COLOUR_TRANSPARENT; - window.scroll_outer = wimp_COLOUR_DARK_GREY; - window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY; - window.highlight_bg = wimp_COLOUR_CREAM; - window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST | - wimp_WINDOW_GIVE_SHADED_ICON_INFO; - window.extent.x0 = 0; - window.extent.y0 = -(window.visible.y1 - window.visible.y0); - window.extent.x1 = window.visible.x1 - window.visible.x0; - window.extent.y1 = 0; - window.title_flags = wimp_ICON_TEXT | - wimp_ICON_INDIRECTED | - wimp_ICON_HCENTRED; - window.work_flags = wimp_BUTTON_DOUBLE_CLICK_DRAG << - wimp_ICON_BUTTON_TYPE_SHIFT; - window.sprite_area = wimpspriteop_AREA; - window.xmin = 1; - window.ymin = 1; - window.title_data.indirected_text.text = g->title; - window.title_data.indirected_text.validation = (char *) -1; - window.title_data.indirected_text.size = 255; - window.icon_count = 0; - - /* Add in flags */ - window.flags |= wimp_WINDOW_SIZE_ICON | - wimp_WINDOW_BACK_ICON | - wimp_WINDOW_CLOSE_ICON | - wimp_WINDOW_TITLE_ICON | - wimp_WINDOW_TOGGLE_ICON; - - if (open_centred) { - int scroll_width = ro_get_vscroll_width(NULL); - window.visible.x0 -= scroll_width; - } - - error = xwimp_create_window(&window, &g->window); - if (error) { - LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - free(g); - return 0; + /* the top-level framed window is a total pain. to get it to maximise + * to the top of the screen we need to fake it having a suitably large + * extent */ + if (browser_window_is_frameset(g->bw)) { + ro_gui_screen_size(&screen_width, &height); + if (g->toolbar) + height -= ro_toolbar_full_height(g->toolbar); + height -= ro_get_hscroll_height(g->window); + height -= ro_get_title_height(g->window); } - - /* Link into window list */ - g->prev = 0; - g->next = window_list; - if (window_list) - window_list->prev = g; - window_list = g; - window_count++; - - /* Add in a toolbar and status bar */ - g->status_bar = ro_gui_status_bar_create(g->window, - nsoption_int(toolbar_status_size)); - g->toolbar = ro_toolbar_create(NULL, g->window, - THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE, - &ro_gui_window_toolbar_callbacks, g, - "HelpToolbar"); - if (g->toolbar != NULL) { - ro_toolbar_add_buttons(g->toolbar, - brower_toolbar_buttons, - nsoption_charp(toolbar_browser)); - ro_toolbar_add_url(g->toolbar); - ro_toolbar_add_throbber(g->toolbar); - ro_toolbar_rebuild(g->toolbar); + if (browser_window_has_content(g->bw)) { + int w, h; + browser_window_get_extents(g->bw, true, &w, &h); + width = max(width, w * 2); + height = max(height, h * 2); } - - /* Register event handlers. Do this quickly, as some of the things - * that follow will indirectly look up our user data: this MUST - * be set first! - */ - ro_gui_wimp_event_set_user_data(g->window, g); - ro_gui_wimp_event_register_open_window(g->window, ro_gui_window_open); - ro_gui_wimp_event_register_close_window(g->window, ro_gui_window_close); - ro_gui_wimp_event_register_redraw_window(g->window, ro_gui_window_redraw); - ro_gui_wimp_event_register_scroll_window(g->window, ro_gui_window_scroll); - ro_gui_wimp_event_register_pointer_entering_window(g->window, ro_gui_window_pointer_entering); - ro_gui_wimp_event_register_keypress(g->window, ro_gui_window_keypress); - ro_gui_wimp_event_register_mouse_click(g->window, ro_gui_window_click); - ro_gui_wimp_event_register_menu(g->window, ro_gui_browser_window_menu, - true, false); - ro_gui_wimp_event_register_menu_prepare(g->window, - ro_gui_window_menu_prepare); - ro_gui_wimp_event_register_menu_selection(g->window, - ro_gui_window_menu_select); - ro_gui_wimp_event_register_menu_warning(g->window, - ro_gui_window_menu_warning); - ro_gui_wimp_event_register_menu_close(g->window, - ro_gui_window_menu_close); - - /* Set the window options */ - ro_gui_window_clone_options(g, existing); - ro_gui_window_update_toolbar_buttons(g); - - /* Open the window at the top of the stack */ - state.w = g->window; - error = xwimp_get_window_state(&state); + os_box extent = { 0, -height, width, toolbar_height }; + error = xwimp_set_extent(g->window, &extent); if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); - return g; + return; } - - state.next = wimp_TOP; - - ro_gui_window_open(PTR_WIMP_OPEN(&state)); - - /* Claim the caret */ - if (ro_toolbar_take_caret(g->toolbar)) - ro_gui_url_complete_start(g->toolbar); - else - gui_window_place_caret(g, -100, -100, 0, NULL); - - return g; } /** - * Close a browser window and free any related resources. + * Open a window * - * \param g gui_window to destroy + * opens a window using the given wimp_open, handling toolbars and resizing. + * + * \param open the window open event information */ - -static void gui_window_destroy(struct gui_window *g) +static void ro_gui_window_open(wimp_open *open) { + struct gui_window *g; + int width = open->visible.x1 - open->visible.x0; + int height = open->visible.y1 - open->visible.y0; + browser_scrolling h_scroll; + browser_scrolling v_scroll; + int toolbar_height = 0; + float new_scale = 0; + wimp_window_state state; os_error *error; - wimp_w w; - - assert(g); - - /* stop any tracking */ - ro_mouse_kill(g); + wimp_w parent; + bits linkage; + bool have_content; - /* remove from list */ - if (g->prev) - g->prev->next = g->next; - else - window_list = g->next; - if (g->next) - g->next->prev = g->prev; + g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w); - /* destroy toolbar */ - if (g->toolbar) - ro_toolbar_destroy(g->toolbar); - if (g->status_bar) - ro_gui_status_bar_destroy(g->status_bar); + if (open->next == wimp_TOP && g->iconise_icon >= 0) { + /* window is no longer iconised, release its sprite number */ + iconise_used[g->iconise_icon] = false; + g->iconise_icon = -1; + } - w = g->window; - ro_gui_url_complete_close(); - ro_gui_dialog_close_persistent(w); - if (current_menu_window == w) - ro_gui_menu_destroy(); - ro_gui_window_remove_update_boxes(g); + have_content = browser_window_has_content(g->bw); - /* delete window */ - error = xwimp_delete_window(w); + /* get the current flags/nesting state */ + state.w = g->window; + error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage); if (error) { - LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); + return; } - ro_gui_wimp_event_finalise(w); - - free(g); -} - -/** - * Set the title of a browser window. - * - * \param g gui_window to update - * \param title new window title, copied - */ - -static void gui_window_set_title(struct gui_window *g, const char *title) -{ - assert(g); - assert(title); - - if (g->scale != 1.0) { - int scale_disp = g->scale * 100; - - if (ABS((float)scale_disp - g->scale * 100) >= 0.05) - snprintf(g->title, sizeof g->title, "%s (%.1f%%)", - title, g->scale * 100); - else - snprintf(g->title, sizeof g->title, "%s (%i%%)", - title, scale_disp); - } else { - strncpy(g->title, title, sizeof g->title); - } + /* account for toolbar height, if present */ + if (g->toolbar) + toolbar_height = ro_toolbar_full_height(g->toolbar); + height -= toolbar_height; - ro_gui_set_window_title(g->window, g->title); -} + /* work with the state from now on so we can modify flags */ + state.visible = open->visible; + state.xscroll = open->xscroll; + state.yscroll = open->yscroll; + state.next = open->next; -/* exported interface documented in riscos/window.h */ -nserror ro_gui_window_invalidate_area(struct gui_window *g, - const struct rect *rect) -{ - bool use_buffer; - int x0, y0, x1, y1; - struct update_box *cur; - wimp_window_info info; - os_error *error; + browser_window_get_scrollbar_type(g->bw, &h_scroll, &v_scroll); - assert(g); + /* handle 'auto' scroll bars' and non-fitting scrollbar removal */ + if ((h_scroll != BW_SCROLLING_NO) && (v_scroll != BW_SCROLLING_NO)) { + int size; - if (rect == NULL) { - info.w = g->window; - error = xwimp_get_window_info_header_only(&info); - if (error) { - LOG("xwimp_get_window_info_header_only: 0x%x: %s", - error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return NSERROR_INVALID; - } + /* windows lose scrollbars when containing a frameset */ + bool no_hscroll = false; + bool no_vscroll = browser_window_is_frameset(g->bw); - error = xwimp_force_redraw(g->window, - info.extent.x0, info.extent.y0, - info.extent.x1, info.extent.y1); - if (error) { - LOG("xwimp_force_redraw: 0x%x: %s", - error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return NSERROR_INVALID; + /* hscroll */ + size = ro_get_hscroll_height(NULL); + size -= 2; /* 1px border on both sides */ + if (!no_hscroll) { + if (!(state.flags & wimp_WINDOW_HSCROLL)) { + height -= size; + state.visible.y0 += size; + if (have_content) { + browser_window_schedule_reformat(g->bw); + } + } + state.flags |= wimp_WINDOW_HSCROLL; + } else { + if (state.flags & wimp_WINDOW_HSCROLL) { + height += size; + state.visible.y0 -= size; + if (have_content) { + browser_window_schedule_reformat(g->bw); + } + } + state.flags &= ~wimp_WINDOW_HSCROLL; } - return NSERROR_OK; - } - - x0 = floorf(rect->x0 * 2 * g->scale); - y0 = -ceilf(rect->y1 * 2 * g->scale); - x1 = ceilf(rect->x1 * 2 * g->scale) + 1; - y1 = -floorf(rect->y0 * 2 * g->scale) + 1; - use_buffer = - (g->option.buffer_everything || g->option.buffer_animations); - /* try to optimise buffered redraws */ - if (use_buffer) { - for (cur = pending_updates; cur != NULL; cur = cur->next) { - if ((cur->g != g) || (!cur->use_buffer)) { - continue; + /* vscroll */ + size = ro_get_vscroll_width(NULL); + size -= 2; /* 1px border on both sides */ + if (!no_vscroll) { + if (!(state.flags & wimp_WINDOW_VSCROLL)) { + width -= size; + state.visible.x1 -= size; + if (have_content) { + browser_window_schedule_reformat(g->bw); + } } - if ((((cur->x0 - x1) < MARGIN) || - ((cur->x1 - x0) < MARGIN)) && - (((cur->y0 - y1) < MARGIN) || - ((cur->y1 - y0) < MARGIN))) { - cur->x0 = min(cur->x0, x0); - cur->y0 = min(cur->y0, y0); - cur->x1 = max(cur->x1, x1); - cur->y1 = max(cur->y1, y1); - return NSERROR_OK; + state.flags |= wimp_WINDOW_VSCROLL; + } else { + if (state.flags & wimp_WINDOW_VSCROLL) { + width += size; + state.visible.x1 += size; + if (have_content) { + browser_window_schedule_reformat(g->bw); + } } + state.flags &= ~wimp_WINDOW_VSCROLL; } } - cur = malloc(sizeof(struct update_box)); - if (!cur) { - LOG("No memory for malloc."); - return NSERROR_NOMEM; - } - cur->x0 = x0; - cur->y0 = y0; - cur->x1 = x1; - cur->y1 = y1; - cur->next = pending_updates; - pending_updates = cur; - cur->g = g; - cur->use_buffer = use_buffer; - - return NSERROR_OK; -} - - -/** - * Get the scroll position of a browser window. - * - * \param g gui_window - * \param sx receives x ordinate of point at top-left of window - * \param sy receives y ordinate of point at top-left of window - * \return true iff successful - */ - -static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) -{ - wimp_window_state state; - os_error *error; - int toolbar_height = 0; - - assert(g); - - state.w = g->window; - error = xwimp_get_window_state(&state); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; + /* reformat or change extent if necessary */ + if (have_content && + (g->old_width != width || g->old_height != height)) { + /* Ctrl-resize of a top-level window scales the content size */ + if ((g->old_width > 0) && (g->old_width != width) && + (ro_gui_ctrl_pressed())) + new_scale = (g->scale * width) / g->old_width; + browser_window_schedule_reformat(g->bw); + } + if (g->update_extent || g->old_width != width || + g->old_height != height) { + g->old_width = width; + g->old_height = height; + g->update_extent = false; + gui_window_set_extent(g, width, height); } - if (g->toolbar) - toolbar_height = ro_toolbar_full_height(g->toolbar); - *sx = state.xscroll / (2 * g->scale); - *sy = -(state.yscroll - toolbar_height) / (2 * g->scale); - return true; -} - + /* first resize stops any flickering by making the URL window on top */ + ro_gui_url_complete_resize(g->toolbar, PTR_WIMP_OPEN(&state)); -/** - * Set the scroll position of a riscos browser window. - * - * Scrolls the viewport to ensure the specified rectangle of the - * content is shown. - * - * \param g gui window to scroll - * \param rect The rectangle to ensure is shown. - * \return NSERROR_OK on success or apropriate error code. - */ -static nserror -gui_window_set_scroll(struct gui_window *g, const struct rect *rect) -{ - wimp_window_state state; - os_error *error; - int toolbar_height = 0; + /* Windows containing framesets can only be scrolled via the core, which + * is implementing frame scrollbars itself. The x and y offsets are + * therefore fixed. + */ - assert(g); + if (browser_window_is_frameset(g->bw)) { + state.xscroll = 0; + state.yscroll = toolbar_height; + } - state.w = g->window; - error = xwimp_get_window_state(&state); + error = xwimp_open_window_nested_with_flags(&state, parent, linkage); if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", - error->errnum, error->errmess); + LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); - return NSERROR_BAD_PARAMETER; + return; } + /* update the toolbar */ + if (g->status_bar) + ro_gui_status_bar_resize(g->status_bar); if (g->toolbar) { - toolbar_height = ro_toolbar_full_height(g->toolbar); - } - - if ((rect->x0 == rect->x1) && (rect->y0 == rect->y1)) { - /* scroll to top */ - state.xscroll = rect->x0 * 2 * g->scale; - state.yscroll = (-rect->y0 * 2 * g->scale) + toolbar_height; - } else { - /* scroll area into view with padding */ - int x0, y0, x1, y1; - int cx0, cy0, width, height; - int padding_available; - int correction; - - x0 = rect->x0 * 2 * g->scale; - y0 = rect->y0 * 2 * g->scale; - x1 = rect->x1 * 2 * g->scale; - y1 = rect->y1 * 2 * g->scale; - - cx0 = state.xscroll; - cy0 = -state.yscroll + toolbar_height; - width = state.visible.x1 - state.visible.x0; - height = state.visible.y1 - state.visible.y0 - toolbar_height; - - /* make sure we're visible */ - correction = (x1 - cx0 - width); - if (correction > 0) { - cx0 += correction; - } - correction = (y1 - cy0 - height); - if (correction > 0) { - cy0 += correction; - } - if (x0 < cx0) { - cx0 = x0; - } - if (y0 < cy0) { - cy0 = y0; - } - - /* try to give a SCROLL_VISIBLE_PADDING border of space around us */ - padding_available = (width - x1 + x0) / 2; - if (padding_available > 0) { - if (padding_available > SCROLL_VISIBLE_PADDING) { - padding_available = SCROLL_VISIBLE_PADDING; - } - correction = (cx0 + width - x1); - if (correction < padding_available) { - cx0 += padding_available; - } - correction = (x0 - cx0); - if (correction < padding_available) { - cx0 -= padding_available; - } - } - padding_available = (height - y1 + y0) / 2; - if (padding_available > 0) { - if (padding_available > SCROLL_VISIBLE_PADDING) { - padding_available = SCROLL_VISIBLE_PADDING; - } - correction = (cy0 + height - y1); - if (correction < padding_available) { - cy0 += padding_available; - } - correction = (y0 - cy0); - if (correction < padding_available) { - cy0 -= padding_available; - } - } - - state.xscroll = cx0; - state.yscroll = -cy0 + toolbar_height; + ro_toolbar_process(g->toolbar, -1, false); + /* second resize updates to the new URL bar width */ + ro_gui_url_complete_resize(g->toolbar, open); } - ro_gui_window_open(PTR_WIMP_OPEN(&state)); - - return NSERROR_OK; -} - -/** - * Find the current dimensions of a browser window's content area. - * - * \param gw gui window to measure - * \param width receives width of window - * \param height receives height of window - * \param scaled whether to return scaled values - */ -static nserror -gui_window_get_dimensions(struct gui_window *gw, - int *width, int *height, - bool scaled) -{ - /* use the cached window sizes */ - *width = gw->old_width / 2; - *height = gw->old_height / 2; - - if (scaled) { - *width /= gw->scale; - *height /= gw->scale; + /* set the new scale from a ctrl-resize. this must be done at the end as + * it may cause a frameset recalculation based on the new window size. + */ + if (new_scale > 0) { + ro_gui_window_set_scale(g, new_scale); } - return NSERROR_OK; } @@ -943,20 +441,20 @@ gui_window_get_dimensions(struct gui_window *gw, * Update the extent of the inside of a browser window to that of the * current content. * - * \param g gui_window to update the extent of + * \param g gui_window to update the extent of */ - static void gui_window_update_extent(struct gui_window *g) { - os_error *error; - wimp_window_info info; + os_error *error; + wimp_window_info info; assert(g); info.w = g->window; error = xwimp_get_window_info_header_only(&info); if (error) { - LOG("xwimp_get_window_info_header_only: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_get_window_info_header_only: 0x%x: %s", + error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); return; } @@ -974,872 +472,736 @@ static void gui_window_update_extent(struct gui_window *g) /** - * Set the status bar of a browser window. + * Update a window and its toolbar * - * \param g gui_window to update - * \param text new status text + * makes a window and toolbar reflect a new theme: used as a callback + * by the toolbar module when a theme change affects a toolbar. + * + * \param data void pointer to the window's gui_window struct + * \param ok true if the bar still exists; else false. */ - -static void riscos_window_set_status(struct gui_window *g, const char *text) +static void ro_gui_window_update_theme(void *data, bool ok) { - if (g->status_bar) - ro_gui_status_bar_set_text(g->status_bar, text); + struct gui_window *g = (struct gui_window *) data; + + if (g != NULL && g->toolbar != NULL) { + if (ok) { + gui_window_update_extent(g); + } else { + g->toolbar = NULL; + } + } } /** - * Change mouse pointer shape + * Update a window to reflect a change in toolbar size: used as a callback by + * the toolbar module when a toolbar height changes. + * + * \param data void pointer the window's gui_window struct */ +static void ro_gui_window_update_toolbar(void *data) +{ + struct gui_window *g = (struct gui_window *) data; -void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) + if (g != NULL) { + gui_window_update_extent(g); + } +} + + +/** + * Update the toolbar buttons for a given browser window to reflect the + * current state of its contents. + * + * Note that the parameters to this function are arranged so that it can be + * supplied to the toolbar module as an button state update callback. + * + * \param g The browser window to update. + */ +static void ro_gui_window_update_toolbar_buttons(struct gui_window *g) { - static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT; - struct ro_gui_pointer_entry *entry; - os_error *error; + struct browser_window *bw; + struct toolbar *toolbar; - if (shape == curr_pointer) + if (g == NULL || g->toolbar == NULL) return; - assert(shape < sizeof ro_gui_pointer_table / - sizeof ro_gui_pointer_table[0]); + bw = g->bw; + toolbar = g->toolbar; - entry = &ro_gui_pointer_table[shape]; + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_RELOAD, + !browser_window_reload_available(bw)); - if (entry->wimp_area) { - /* pointer in the Wimp's sprite area */ - error = xwimpspriteop_set_pointer_shape(entry->sprite_name, - 1, entry->xactive, entry->yactive, 0, 0); - if (error) { - LOG("xwimpspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - } - } else { - /* pointer in our own sprite area */ - error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA, - gui_sprites, - (osspriteop_id) entry->sprite_name, - 1, entry->xactive, entry->yactive, 0, 0); - if (error) { - LOG("xosspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - } - } + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_STOP, + !browser_window_stop_available(bw)); - curr_pointer = shape; -} + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_BACK, + !browser_window_back_available(bw)); + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_FORWARD, + !browser_window_forward_available(bw)); -/* exported function documented in riscos/window.h */ -nserror ro_gui_window_set_url(struct gui_window *g, nsurl *url) -{ - size_t idn_url_l; - char *idn_url_s = NULL; + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_UP, + !browser_window_up_available(bw)); - if (g->toolbar) { - if (nsoption_bool(display_decoded_idn) == true) { - if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) - idn_url_s = NULL; - } + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SEARCH, + !browser_window_can_search(bw)); - ro_toolbar_set_url(g->toolbar, idn_url_s ? idn_url_s : nsurl_access(url), true, false); + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SCALE, + !browser_window_has_content(bw)); - if (idn_url_s) - free(idn_url_s); + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_PRINT, + !browser_window_has_content(bw)); - ro_gui_url_complete_start(g->toolbar); - } + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SAVE_SOURCE, + !browser_window_has_content(bw)); - return NSERROR_OK; + ro_toolbar_update_urlsuggest(toolbar); } /** - * Update the interface to reflect start of page loading. + * Add a hotlist entry for a browser window. * - * \param g window with start of load + * \param g The browser window to act on. */ - -static void gui_window_start_throbber(struct gui_window *g) +static void ro_gui_window_action_add_bookmark(struct gui_window *g) { - ro_gui_window_update_toolbar_buttons(g); - ro_gui_menu_refresh(ro_gui_browser_window_menu); - if (g->toolbar != NULL) - ro_toolbar_start_throbbing(g->toolbar); - g->active = true; -} - + nsurl *url; + if (g == NULL || g->bw == NULL || g->toolbar == NULL || + browser_window_has_content(g->bw) == false) + return; -/** - * Update the interface to reflect page loading stopped. - * - * \param g window with start of load - */ + url = browser_window_get_url(g->bw); -static void gui_window_stop_throbber(struct gui_window *g) -{ - ro_gui_window_update_toolbar_buttons(g); - ro_gui_menu_refresh(ro_gui_browser_window_menu); - if (g->toolbar != NULL) - ro_toolbar_stop_throbbing(g->toolbar); - g->active = false; + ro_gui_hotlist_add_page(url); + ro_toolbar_update_hotlist(g->toolbar); } + /** - * set favicon + * Remove a hotlist entry for a browser window. + * + * \param g The browser window to act on. */ - -static void gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon) +static void ro_gui_window_action_remove_bookmark(struct gui_window *g) { - if (g == NULL || g->toolbar == NULL) + nsurl *url; + + if (g == NULL || g->bw == NULL || g->toolbar == NULL || + browser_window_has_content(g->bw) == false) return; - ro_toolbar_set_site_favicon(g->toolbar, icon); -} + url = browser_window_get_url(g->bw); + ro_gui_hotlist_remove_page(url); +} /** - * Remove the caret, if present. + * Open a local history pane for a browser window. * - * \param g window with caret + * \param gw The browser window to act on. */ - -static void gui_window_remove_caret(struct gui_window *g) +static void ro_gui_window_action_local_history(struct gui_window *gw) { - wimp_caret caret; - os_error *error; + nserror res; - error = xwimp_get_caret_position(&caret); - if (error) { - LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); + if ((gw == NULL) || (gw->bw == NULL)) { return; } - if (caret.w != g->window) - /* we don't have the caret: do nothing */ - return; + res = ro_gui_local_history_present(gw->window, gw->bw); - /* hide caret, but keep input focus */ - gui_window_place_caret(g, -100, -100, 0, NULL); + if (res != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(res), 0); + } } /** - * Called when the gui_window has new content. + * Perform a Navigate Home action on a browser window. * - * \param g the gui_window that has new content + * \param g The browser window to act on. */ - -static void gui_window_new_content(struct gui_window *g) +static void ro_gui_window_action_home(struct gui_window *g) { - ro_gui_menu_refresh(ro_gui_browser_window_menu); - ro_gui_window_update_toolbar_buttons(g); - ro_gui_dialog_close_persistent(g->window); - ro_toolbar_set_content_favicon(g->toolbar, g); -} - - -/** - * Starts drag scrolling of a browser window - * - * \param g the window to scroll - */ + static const char *addr = NETSURF_HOMEPAGE; + nsurl *url; + nserror error; -static bool gui_window_scroll_start(struct gui_window *g) -{ - wimp_window_info_base info; - wimp_pointer pointer; - os_error *error; - wimp_drag drag; - int height; - int width; + if (g == NULL || g->bw == NULL) + return; - error = xwimp_get_pointer_info(&pointer); - if (error) { - LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; + if (nsoption_charp(homepage_url) != NULL) { + addr = nsoption_charp(homepage_url); } - info.w = g->window; - error = xwimp_get_window_info_header_only((wimp_window_info*)&info); - if (error) { - LOG("xwimp_get_window_state: 0x%x : %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; + error = nsurl_create(addr, &url); + if (error == NSERROR_OK) { + error = browser_window_navigate(g->bw, + url, + NULL, + BW_NAVIGATE_HISTORY, + NULL, + NULL, + NULL); + nsurl_unref(url); } - - width = info.extent.x1 - info.extent.x0; - height = info.extent.y1 - info.extent.y0; - - drag.type = wimp_DRAG_USER_POINT; - drag.bbox.x1 = pointer.pos.x + info.xscroll; - drag.bbox.y0 = pointer.pos.y + info.yscroll; - drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0)); - drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0)); - - if (g->toolbar) { - int tbar_height = ro_toolbar_full_height(g->toolbar); - drag.bbox.y0 -= tbar_height; - drag.bbox.y1 -= tbar_height; + if (error != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(error), 0); } +} - error = xwimp_drag_box(&drag); - if (error) { - LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at, - NULL, g); - return true; +/** + * Open a text search dialogue for a browser window. + * + * \param g The browser window to act on. + */ +static void ro_gui_window_action_search(struct gui_window *g) +{ + if (g == NULL || g->bw == NULL || !browser_window_can_search(g->bw)) + return; + + ro_gui_search_prepare(g->bw); + ro_gui_dialog_open_persistent(g->window, dialog_search, true); } /** - * Platform-dependent part of starting drag operation. + * Open a zoom dialogue for a browser window. * - * \param g gui window containing the drag - * \param type type of drag the core is performing - * \param rect rectangle to constrain pointer to (relative to drag start coord) - * \return true iff succesful + * \param g The browser window to act on. */ - -static bool gui_window_drag_start(struct gui_window *g, gui_drag_type type, - const struct rect *rect) +static void ro_gui_window_action_zoom(struct gui_window *g) { - wimp_pointer pointer; - wimp_drag drag; + if (g == NULL) + return; - if (rect != NULL) { - /* We have a box to constrain the pointer to, for the drag - * duration */ - os_error *error = xwimp_get_pointer_info(&pointer); - if (error) { - LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } + ro_gui_dialog_prepare_zoom(g); + ro_gui_dialog_open_persistent(g->window, dialog_zoom, true); +} - drag.type = wimp_DRAG_USER_POINT; - drag.bbox.x0 = pointer.pos.x + - (int)(rect->x0 * 2 * g->scale); - drag.bbox.y0 = pointer.pos.y + - (int)(rect->y0 * 2 * g->scale); - drag.bbox.x1 = pointer.pos.x + - (int)(rect->x1 * 2 * g->scale); - drag.bbox.y1 = pointer.pos.y + - (int)(rect->y1 * 2 * g->scale); - error = xwimp_drag_box(&drag); - if (error) { - LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - } +/** + * Open a save dialogue for a browser window contents. + * + * \param g The browser window to act on. + * \param save_type The type of save to open. + */ +static void +ro_gui_window_action_save(struct gui_window *g, gui_save_type save_type) +{ + struct hlcache_handle *h; - switch (type) { - case GDRAGGING_SCROLLBAR: - /* Dragging a core scrollbar */ - ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at, - NULL, g); - break; + if (g == NULL || g->bw == NULL || !browser_window_has_content(g->bw)) + return; - default: - /* Not handled here yet */ - break; - } + h = browser_window_get_content(g->bw); + if (h == NULL) + return; - return true; + ro_gui_save_prepare(save_type, h, NULL, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); } /** - * Save the specified content as a link. + * Open a print dialogue for a browser window. * - * \param g The window containing the content - * \param url The url of the link - * \param title The title of the link + * \param g The browser window to act on. */ -static nserror -gui_window_save_link(struct gui_window *g, nsurl *url, const char *title) +static void ro_gui_window_action_print(struct gui_window *g) { - ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); - return NSERROR_OK; + if (g != NULL) { + ro_gui_print_prepare(g); + ro_gui_dialog_open_persistent(g->window, dialog_print, true); + } } /** - * Updates a windows extent. + * Prepare the page info window for use. * - * \param g the gui_window to update - * \param width the minimum width, or -1 to use window width - * \param height the minimum height, or -1 to use window height + * \param g The GUI window block to use. */ - -void gui_window_set_extent(struct gui_window *g, int width, int height) +static void ro_gui_window_prepare_pageinfo(struct gui_window *g) { - int screen_width; - int toolbar_height = 0; - wimp_window_state state; - os_error *error; + struct hlcache_handle *h = browser_window_get_content(g->bw); + char icon_buf[20] = "file_xxx"; + char enc_buf[40]; + const char *icon = icon_buf; + const char *title, *url; + lwc_string *mime; + const char *enc = "-"; - if (g->toolbar) - toolbar_height = ro_toolbar_full_height(g->toolbar); + assert(h); - /* get the current state */ - if ((height == -1) || (width == -1)) { - state.w = g->window; - error = xwimp_get_window_state(&state); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return; - } - if (width == -1) - width = state.visible.x1 - state.visible.x0; - if (height == -1) { - height = state.visible.y1 - state.visible.y0; - height -= toolbar_height; + title = content_get_title(h); + if (title == NULL) + title = "-"; + url = nsurl_access(hlcache_handle_get_url(h)); + if (url == NULL) + url = "-"; + mime = content_get_mime_type(h); + + sprintf(icon_buf, "file_%x", ro_content_filetype(h)); + if (!ro_gui_wimp_sprite_exists(icon_buf)) + sprintf(icon_buf, "file_xxx"); + + if (content_get_type(h) == CONTENT_HTML) { + if (content_get_encoding(h, CONTENT_ENCODING_NORMAL)) { + snprintf(enc_buf, sizeof enc_buf, "%s (%s)", + content_get_encoding(h, CONTENT_ENCODING_NORMAL), + content_get_encoding(h, CONTENT_ENCODING_SOURCE)); + enc = enc_buf; + } else { + enc = messages_get("EncodingUnk"); } } - /* the top-level framed window is a total pain. to get it to maximise - * to the top of the screen we need to fake it having a suitably large - * extent */ - if (browser_window_is_frameset(g->bw)) { - ro_gui_screen_size(&screen_width, &height); - if (g->toolbar) - height -= ro_toolbar_full_height(g->toolbar); - height -= ro_get_hscroll_height(g->window); - height -= ro_get_title_height(g->window); - } - if (browser_window_has_content(g->bw)) { - int w, h; - browser_window_get_extents(g->bw, true, &w, &h); - width = max(width, w * 2); - height = max(height, h * 2); - } - os_box extent = { 0, -height, width, toolbar_height }; - error = xwimp_set_extent(g->window, &extent); - if (error) { - LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return; - } + ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ICON, + icon, true); + ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TITLE, + title, true); + ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_URL, + url, true); + ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC, + enc, true); + ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE, + lwc_string_data(mime), true); + + lwc_string_unref(mime); } /** - * Display a menu of options for a form select control. + * Open a page info box for a browser window. * - * \param g gui window containing form control - * \param control form control of type GADGET_SELECT + * \param g The browser window to act on. */ - -static void gui_window_create_form_select_menu(struct gui_window *g, - struct form_control *control) +static void ro_gui_window_action_page_info(struct gui_window *g) { - os_error *error; - wimp_pointer pointer; + if (g == NULL || g->bw == NULL || + browser_window_has_content(g->bw) == false) + return; - /* The first time the menu is opened, control bypasses the normal - * Menu Prepare event and so we prepare here. On any re-opens, - * ro_gui_window_prepare_form_select_menu() is called from the - * normal wimp event. - */ + ro_gui_window_prepare_pageinfo(g); + ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, false); +} - if (!ro_gui_window_prepare_form_select_menu(g, control)) - return; - error = xwimp_get_pointer_info(&pointer); - if (error) { - LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - ro_gui_menu_destroy(); +/** + * Process Mouse_Click events in a toolbar's button bar. + * + * This does not handle other clicks in a toolbar: these are handled + * by the toolbar module itself. + * + * \param data The GUI window associated with the click. + * \param action_type The action type to be handled. + * \param action The action to process. + */ +static void +ro_gui_window_toolbar_click(void *data, + toolbar_action_type action_type, + union toolbar_action action) +{ + struct gui_window *g = data; + nserror err; + + if (g == NULL) return; - } - gui_form_select_control = control; - ro_gui_menu_create(gui_form_select_menu, - pointer.pos.x, pointer.pos.y, g->window); -} + if (action_type == TOOLBAR_ACTION_URL) { + switch (action.url) { + case TOOLBAR_URL_DRAG_URL: + { + gui_save_type save_type; -/* - * RISC OS Wimp Event Handlers - */ + if (!browser_window_has_content(g->bw)) + break; + if (ro_gui_shift_pressed()) + save_type = GUI_SAVE_LINK_URL; + else + save_type = GUI_SAVE_LINK_TEXT; -/** - * Handle a Redraw_Window_Request for a browser window. - */ + ro_gui_drag_save_link(save_type, + browser_window_get_url(g->bw), + browser_window_get_title(g->bw), g); + } + break; -void ro_gui_window_redraw(wimp_draw *redraw) -{ - osbool more; - struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w); - os_error *error; - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = &ro_plotters - }; + case TOOLBAR_URL_SELECT_HOTLIST: + ro_gui_window_action_add_bookmark(g); + break; - /* We can't render locked contents. If the browser window is not - * ready for redraw, do nothing. Else, in the case of buffered - * rendering we'll show random data. */ - if (!browser_window_redraw_ready(g->bw)) - return; + case TOOLBAR_URL_ADJUST_HOTLIST: + ro_gui_window_action_remove_bookmark(g); + break; - ro_gui_current_redraw_gui = g; + default: + break; + } - error = xwimp_redraw_window(redraw, &more); - if (error) { - LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); return; } - while (more) { - struct rect clip; - /* OS's redraw request coordinates are in screen coordinates, - * with an origin at the bottom left of the screen. - * Find the coordinate of the top left of the document in terms - * of OS screen coordinates. - * NOTE: OS units are 2 per px. */ - ro_plot_origin_x = redraw->box.x0 - redraw->xscroll; - ro_plot_origin_y = redraw->box.y1 - redraw->yscroll; - /* Convert OS redraw rectangle request coordinates into NetSurf - * coordinates. NetSurf coordinates have origin at top left of - * document and units are in px. */ - clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */ - clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */ - clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */ - clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */ + /* By now, the only valid action left is a button click. If it isn't + * one of those, give up. + */ - if (ro_gui_current_redraw_gui->option.buffer_everything) - ro_gui_buffer_open(redraw); + if (action_type != TOOLBAR_ACTION_BUTTON) + return; - browser_window_redraw(g->bw, 0, 0, &clip, &ctx); + switch (action.button) { + case TOOLBAR_BUTTON_BACK: + if (g->bw != NULL) + browser_window_history_back(g->bw, false); + break; - if (ro_gui_current_redraw_gui->option.buffer_everything) - ro_gui_buffer_close(); + case TOOLBAR_BUTTON_BACK_NEW: + if (g->bw != NULL) + browser_window_history_back(g->bw, true); + break; - /* Check to see if there are more rectangles to draw and - * get next one */ - error = xwimp_get_rectangle(redraw, &more); - /* RISC OS 3.7 returns an error here if enough buffer was - claimed to cause a new dynamic area to be created. It - doesn't actually stop anything working, so we mask it out - for now until a better fix is found. This appears to be a - bug in RISC OS. */ - if (error && !(ro_gui_current_redraw_gui-> - option.buffer_everything && - error->errnum == error_WIMP_GET_RECT)) { - LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - ro_gui_current_redraw_gui = NULL; - return; - } - } - ro_gui_current_redraw_gui = NULL; -} + case TOOLBAR_BUTTON_FORWARD: + if (g->bw != NULL) + browser_window_history_forward(g->bw, false); + break; + case TOOLBAR_BUTTON_FORWARD_NEW: + if (g->bw != NULL) + browser_window_history_forward(g->bw, true); + break; -/** - * Set a gui_window's scale - */ -void ro_gui_window_set_scale(struct gui_window *g, float scale) -{ - g->scale = scale; - browser_window_set_scale(g->bw, scale, true); -} + case TOOLBAR_BUTTON_STOP: + if (g->bw != NULL) + browser_window_stop(g->bw); + break; + case TOOLBAR_BUTTON_RELOAD: + if (g->bw != NULL) + browser_window_reload(g->bw, false); + break; -/** - * Open a window using the given wimp_open, handling toolbars and resizing. - */ + case TOOLBAR_BUTTON_RELOAD_ALL: + if (g->bw != NULL) + browser_window_reload(g->bw, true); + break; -void ro_gui_window_open(wimp_open *open) -{ - struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w); - int width = open->visible.x1 - open->visible.x0; - int height = open->visible.y1 - open->visible.y0; - browser_scrolling h_scroll; - browser_scrolling v_scroll; - int toolbar_height = 0; - float new_scale = 0; - wimp_window_state state; - os_error *error; - wimp_w parent; - bits linkage; - bool have_content; + case TOOLBAR_BUTTON_HISTORY_LOCAL: + ro_gui_window_action_local_history(g); + break; - if (open->next == wimp_TOP && g->iconise_icon >= 0) { - /* window is no longer iconised, release its sprite number */ - iconise_used[g->iconise_icon] = false; - g->iconise_icon = -1; - } + case TOOLBAR_BUTTON_HISTORY_GLOBAL: + ro_gui_global_history_present(); + break; - have_content = browser_window_has_content(g->bw); + case TOOLBAR_BUTTON_HOME: + ro_gui_window_action_home(g); + break; - /* get the current flags/nesting state */ - state.w = g->window; - error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return; - } + case TOOLBAR_BUTTON_SEARCH: + ro_gui_window_action_search(g); + break; - /* account for toolbar height, if present */ - if (g->toolbar) - toolbar_height = ro_toolbar_full_height(g->toolbar); - height -= toolbar_height; + case TOOLBAR_BUTTON_SCALE: + ro_gui_window_action_zoom(g); + break; - /* work with the state from now on so we can modify flags */ - state.visible = open->visible; - state.xscroll = open->xscroll; - state.yscroll = open->yscroll; - state.next = open->next; + case TOOLBAR_BUTTON_BOOKMARK_OPEN: + ro_gui_hotlist_present(); + break; - browser_window_get_scrollbar_type(g->bw, &h_scroll, &v_scroll); + case TOOLBAR_BUTTON_BOOKMARK_ADD: + ro_gui_window_action_add_bookmark(g); + break; - /* handle 'auto' scroll bars' and non-fitting scrollbar removal */ - if ((h_scroll != BW_SCROLLING_NO) && (v_scroll != BW_SCROLLING_NO)) { - int size; + case TOOLBAR_BUTTON_SAVE_SOURCE: + ro_gui_window_action_save(g, GUI_SAVE_SOURCE); + break; - /* windows lose scrollbars when containing a frameset */ - bool no_hscroll = false; - bool no_vscroll = browser_window_is_frameset(g->bw); + case TOOLBAR_BUTTON_SAVE_COMPLETE: + ro_gui_window_action_save(g, GUI_SAVE_COMPLETE); + break; - /* hscroll */ - size = ro_get_hscroll_height(NULL); - size -= 2; /* 1px border on both sides */ - if (!no_hscroll) { - if (!(state.flags & wimp_WINDOW_HSCROLL)) { - height -= size; - state.visible.y0 += size; - if (have_content) { - browser_window_schedule_reformat(g->bw); - } - } - state.flags |= wimp_WINDOW_HSCROLL; - } else { - if (state.flags & wimp_WINDOW_HSCROLL) { - height += size; - state.visible.y0 -= size; - if (have_content) { - browser_window_schedule_reformat(g->bw); - } - } - state.flags &= ~wimp_WINDOW_HSCROLL; + case TOOLBAR_BUTTON_PRINT: + ro_gui_window_action_print(g); + break; + + case TOOLBAR_BUTTON_UP: + err = browser_window_navigate_up(g->bw, false); + if (err != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(err), NULL); } + break; - /* vscroll */ - size = ro_get_vscroll_width(NULL); - size -= 2; /* 1px border on both sides */ - if (!no_vscroll) { - if (!(state.flags & wimp_WINDOW_VSCROLL)) { - width -= size; - state.visible.x1 -= size; - if (have_content) { - browser_window_schedule_reformat(g->bw); - } - } - state.flags |= wimp_WINDOW_VSCROLL; - } else { - if (state.flags & wimp_WINDOW_VSCROLL) { - width += size; - state.visible.x1 += size; - if (have_content) { - browser_window_schedule_reformat(g->bw); - } - } - state.flags &= ~wimp_WINDOW_VSCROLL; + case TOOLBAR_BUTTON_UP_NEW: + err = browser_window_navigate_up(g->bw, true); + if (err != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(err), NULL); } - } + break; - /* reformat or change extent if necessary */ - if (have_content && - (g->old_width != width || g->old_height != height)) { - /* Ctrl-resize of a top-level window scales the content size */ - if ((g->old_width > 0) && (g->old_width != width) && - (ro_gui_ctrl_pressed())) - new_scale = (g->scale * width) / g->old_width; - browser_window_schedule_reformat(g->bw); - } - if (g->update_extent || g->old_width != width || - g->old_height != height) { - g->old_width = width; - g->old_height = height; - g->update_extent = false; - gui_window_set_extent(g, width, height); + default: + break; } - /* first resize stops any flickering by making the URL window on top */ - ro_gui_url_complete_resize(g->toolbar, PTR_WIMP_OPEN(&state)); + ro_gui_window_update_toolbar_buttons(g); +} - /* Windows containing framesets can only be scrolled via the core, which - * is implementing frame scrollbars itself. The x and y offsets are - * therefore fixed. - */ - if (browser_window_is_frameset(g->bw)) { - state.xscroll = 0; - state.yscroll = toolbar_height; - } +/** + * Launch a new url in the given window. + * + * \param g gui_window to update + * \param url1 url to be launched + */ +static void ro_gui_window_launch_url(struct gui_window *g, const char *url1) +{ + nserror error; + nsurl *url; - error = xwimp_open_window_nested_with_flags(&state, parent, linkage); - if (error) { - LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); + if (url1 == NULL) return; - } - /* update the toolbar */ - if (g->status_bar) - ro_gui_status_bar_resize(g->status_bar); - if (g->toolbar) { - ro_toolbar_process(g->toolbar, -1, false); - /* second resize updates to the new URL bar width */ - ro_gui_url_complete_resize(g->toolbar, open); - } + ro_gui_url_complete_close(); - /* set the new scale from a ctrl-resize. this must be done at the end as - * it may cause a frameset recalculation based on the new window size. - */ - if (new_scale > 0) { - ro_gui_window_set_scale(g, new_scale); + error = nsurl_create(url1, &url); + if (error != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(error), 0); + } else { + ro_gui_window_set_url(g, url); + + browser_window_navigate(g->bw, url, + NULL, BW_NAVIGATE_HISTORY, + NULL, NULL, NULL); + nsurl_unref(url); } } /** - * Handle wimp closing event + * Open a new browser window. + * + * \param g The browser window to act on. */ - -void ro_gui_window_close(wimp_w w) +static void ro_gui_window_action_new_window(struct gui_window *g) { - struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w); - wimp_pointer pointer; - os_error *error; - char *temp_name; - char *filename = NULL; - struct nsurl *url; - bool destroy; + nserror error; - error = xwimp_get_pointer_info(&pointer); - if (error) { - LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); + if (g == NULL || g->bw == NULL) return; - } - if (pointer.buttons & wimp_CLICK_ADJUST) { - destroy = !ro_gui_shift_pressed(); + error = browser_window_create(BW_CREATE_CLONE, + browser_window_get_url(g->bw), + NULL, g->bw, NULL); - url = browser_window_get_url(g->bw); - if (url != NULL) { - netsurf_nsurl_to_path(url, &filename); - } - if (filename != NULL) { - temp_name = malloc(strlen(filename) + 32); - if (temp_name) { - char *r; - sprintf(temp_name, "Filer_OpenDir %s", - filename); - r = temp_name + strlen(temp_name); - while (r > temp_name) { - if (*r == '.') { - *r = '\0'; - break; - } - r--; - } - error = xos_cli(temp_name); - if (error) { - LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("MiscError", error->errmess); - return; - } - free(temp_name); - } - free(filename); - } else { - /* this is pointless if we are about to close the - * window */ - if (!destroy && url != NULL) - browser_window_navigate_up(g->bw, false); - } + if (error != NSERROR_OK) { + ro_warn_user(messages_get_errorcode(error), 0); } - else - destroy = true; - - if (destroy) - browser_window_destroy(g->bw); } /** - * Handle Mouse_Click events in a browser window. This should never see - * Menu clicks, as these will be routed to the menu handlers. + * Scroll a browser window. + * + * the scroll is either via the core or directly using the normal + * Wimp_OpenWindow interface. + * + * Scroll steps are supplied in terms of the (extended) Scroll Event direction + * values returned by Wimp_Poll. Special values of 0x7fffffff and 0x80000000 + * are added to mean "Home" and "End". * - * \param *pointer details of mouse click - * \return true if click handled, false otherwise + * \param g The GUI Window to be scrolled. + * \param scroll_x The X scroll step to be applied. + * \param scroll_y The Y scroll step to be applied. */ - -bool ro_gui_window_click(wimp_pointer *pointer) +static void +ro_gui_window_scroll_action(struct gui_window *g, + wimp_scroll_direction scroll_x, + wimp_scroll_direction scroll_y) { - struct gui_window *g; - os_coord pos; + int visible_x, visible_y; + int step_x = 0, step_y = 0; + int toolbar_y; + wimp_window_state state; + wimp_pointer pointer; + os_error *error; + os_coord pos; + bool handled = false; + struct toolbar *toolbar; - /* We should never see Menu clicks. */ + if (g == NULL) + return; - if (pointer->buttons == wimp_CLICK_MENU) - return false; + /* Get the current window, toolbar and pointer details. */ - g = (struct gui_window *) ro_gui_wimp_event_get_user_data(pointer->w); + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + return; + } - /* try to close url-completion */ - ro_gui_url_complete_close(); + toolbar = ro_toolbar_parent_window_lookup(g->window); + assert(g == NULL || g->toolbar == NULL || g->toolbar == toolbar); - /* set input focus */ - if (pointer->buttons & (wimp_SINGLE_SELECT | wimp_SINGLE_ADJUST)) - gui_window_place_caret(g, -100, -100, 0, NULL); + toolbar_y = (toolbar == NULL) ? 0 : ro_toolbar_full_height(toolbar); - if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) - browser_window_mouse_click(g->bw, - ro_gui_mouse_click_state(pointer->buttons, - wimp_BUTTON_DOUBLE_CLICK_DRAG), - pos.x, pos.y); + visible_x = state.visible.x1 - state.visible.x0 - 32; + visible_y = state.visible.y1 - state.visible.y0 - 32 - toolbar_y; - return true; -} + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + /* Turn the scroll requirement from Scroll Event codes into coordinates + * that the core can understand. + */ -/** - * Process Key_Pressed events in a browser window. - * - * \param *key The wimp keypress block for the event. - * \return true if the event was handled, else false. - */ + switch (scroll_x) { + case wimp_SCROLL_PAGE_LEFT: + step_x = SCROLL_PAGE_DOWN; + break; + case wimp_SCROLL_AUTO_LEFT: + case wimp_SCROLL_COLUMN_LEFT: + step_x = -16; + break; + case wimp_SCROLL_AUTO_RIGHT: + case wimp_SCROLL_COLUMN_RIGHT: + step_x = 16; + break; + case wimp_SCROLL_PAGE_RIGHT: + step_x = SCROLL_PAGE_UP; + break; + case 0x80000000: + step_x = SCROLL_BOTTOM; + break; + case 0x7fffffff: + step_x = SCROLL_TOP; + break; + default: + step_x = (visible_x * (scroll_x>>2)) >> 2; + break; + } -bool ro_gui_window_keypress(wimp_key *key) -{ - struct gui_window *g; - uint32_t c = (uint32_t) key->c; + switch (scroll_y) { + case wimp_SCROLL_PAGE_UP: + step_y = SCROLL_PAGE_UP; + break; + case wimp_SCROLL_AUTO_UP: + case wimp_SCROLL_LINE_UP: + step_y = -16; + break; + case wimp_SCROLL_AUTO_DOWN: + case wimp_SCROLL_LINE_DOWN: + step_y = 16; + break; + case wimp_SCROLL_PAGE_DOWN: + step_y = SCROLL_PAGE_DOWN; + break; + case 0x80000000: + step_y = SCROLL_BOTTOM; + break; + case 0x7fffffff: + step_y = SCROLL_TOP; + break; + default: + step_y = -((visible_y * (scroll_y>>2)) >> 2); + break; + } - g = (struct gui_window *) ro_gui_wimp_event_get_user_data(key->w); - if (g == NULL) - return false; + /* If no scrolling is required, there's no point trying to do any. */ - /* First send the key to the browser window, eg. form fields. */ + if (step_x == 0 && step_y == 0) + return; - if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) || - (c & IS_WIMP_KEY)) { - /* Munge control keys into unused control chars */ - /* We can't map onto 1->26 (reserved for ctrl+<qwerty> - That leaves 27->31 and 128->159 */ - switch (c & ~IS_WIMP_KEY) { - case wimp_KEY_TAB: c = 9; break; - case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; + /* If the pointer is over the window being scrolled, then try to get + * the core to do the scrolling on the object under the pointer. + */ - /* cursor movement keys */ - case wimp_KEY_HOME: - case wimp_KEY_CONTROL | wimp_KEY_LEFT: - c = NS_KEY_LINE_START; + if (pointer.w == g->window && + ro_gui_window_to_window_pos(g, + pointer.pos.x, pointer.pos.y, &pos)) + handled = browser_window_scroll_at_point(g->bw, pos.x, pos.y, + step_x, step_y); + + /* If the core didn't do the scrolling, handle it via the Wimp. + * Windows which contain frames can only be scrolled by the core, + * because it implements frame scroll bars. + */ + + if (!handled && (browser_window_is_frameset(g->bw) == false)) { + switch (step_x) { + case SCROLL_TOP: + state.xscroll -= 0x10000000; break; - case wimp_KEY_END: - if (os_version >= RISCOS5) - c = NS_KEY_LINE_END; - else - c = NS_KEY_DELETE_RIGHT; + case SCROLL_BOTTOM: + state.xscroll += 0x10000000; break; - case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = NS_KEY_LINE_END; break; - case wimp_KEY_CONTROL | wimp_KEY_UP: c = NS_KEY_TEXT_START; break; - case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = NS_KEY_TEXT_END; break; - case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = NS_KEY_WORD_LEFT ; break; - case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = NS_KEY_WORD_RIGHT; break; - case wimp_KEY_SHIFT | wimp_KEY_UP: c = NS_KEY_PAGE_UP; break; - case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = NS_KEY_PAGE_DOWN; break; - case wimp_KEY_LEFT: c = NS_KEY_LEFT; break; - case wimp_KEY_RIGHT: c = NS_KEY_RIGHT; break; - case wimp_KEY_UP: c = NS_KEY_UP; break; - case wimp_KEY_DOWN: c = NS_KEY_DOWN; break; - - /* editing */ - case wimp_KEY_CONTROL | wimp_KEY_END: - c = NS_KEY_DELETE_LINE_END; + case SCROLL_PAGE_UP: + state.xscroll += visible_x; break; - case wimp_KEY_DELETE: - if (ro_gui_ctrl_pressed()) - c = NS_KEY_DELETE_LINE_START; - else if (os_version < RISCOS5) - c = NS_KEY_DELETE_LEFT; + case SCROLL_PAGE_DOWN: + state.xscroll -= visible_x; break; + default: + state.xscroll += 2 * step_x; + break; + } - case wimp_KEY_F8: - c = NS_KEY_UNDO; + switch (step_y) { + case SCROLL_TOP: + state.yscroll += 0x10000000; break; - case wimp_KEY_F9: - c = NS_KEY_REDO; + case SCROLL_BOTTOM: + state.yscroll -= 0x10000000; + break; + case SCROLL_PAGE_UP: + state.yscroll += visible_y; + break; + case SCROLL_PAGE_DOWN: + state.yscroll -= visible_y; break; - default: + state.yscroll -= 2 * step_y; break; } - } - if (!(c & IS_WIMP_KEY)) { - if (browser_window_key_press(g->bw, c)) - return true; + error = xwimp_open_window((wimp_open *) &state); + if (error) { + LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); + } } - - return ro_gui_window_handle_local_keypress(g, key, false); } /** - * Callback handler for keypresses within browser window toolbars. + * Handle keypresses within the RISC OS GUI * - * \param *data Client data, pointing to the GUI Window. - * \param *key The keypress data. - * \return true if the keypress was handled; else false. - */ - -bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key) -{ - struct gui_window *g = (struct gui_window *) data; - - if (g != NULL) - return ro_gui_window_handle_local_keypress(g, key, true); - - return false; -} - - -/** - * Handle keypresses within the RISC OS GUI: this is to be called after the - * core has been given a chance to act, or on keypresses in the toolbar where - * the core doesn't get involved. + * this is to be called after the core has been given a chance to act, + * or on keypresses in the toolbar where the core doesn't get + * involved. * - * \param *g The gui window to which the keypress applies. - * \param *key The keypress data. - * \param is_toolbar true if the keypress is from a toolbar; - * else false. - * \return true if the keypress was claimed; else false. + * \param *g The gui window to which the keypress applies. + * \param *key The keypress data. + * \param is_toolbar true if the keypress is from a toolbar else false. + * \return true if the keypress was claimed; else false. */ - -bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key, - bool is_toolbar) +static bool +ro_gui_window_handle_local_keypress(struct gui_window *g, + wimp_key *key, + bool is_toolbar) { struct browser_window_features cont; os_error *ro_error; @@ -2102,18 +1464,643 @@ bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key, /** - * Prepare the browser window menu for (re-)opening + * Callback handler for keypresses within browser window toolbars. * - * \param w The window owning the menu. - * \param i The icon owning the menu. - * \param *menu The menu about to be opened. - * \param *pointer Pointer to the relevant wimp event block, or - * NULL for an Adjust click. - * \return true if the event was handled; else false. + * \param data Client data, pointing to the GUI Window. + * \param key The keypress data. + * \return true if the keypress was handled; else false. */ +static bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key) +{ + struct gui_window *g = (struct gui_window *) data; -bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_pointer *pointer) + if (g != NULL) { + return ro_gui_window_handle_local_keypress(g, key, true); + } + + return false; +} + + +/** + * Save a new toolbar button configuration + * + * used as a callback by the toolbar module when a buttonbar edit has + * finished. + * + * \param data void pointer to the window's gui_window struct + * \param config pointer to a malloc()'d button config string. + */ +static void ro_gui_window_save_toolbar_buttons(void *data, char *config) +{ + nsoption_set_charp(toolbar_browser, config); + ro_gui_save_options(); +} + + +/** + * toolbar callbacks for a browser window. + */ +static const struct toolbar_callbacks ro_gui_window_toolbar_callbacks = { + ro_gui_window_update_theme, + ro_gui_window_update_toolbar, + (void (*)(void *)) ro_gui_window_update_toolbar_buttons, + ro_gui_window_toolbar_click, + ro_gui_window_toolbar_keypress, + ro_gui_window_save_toolbar_buttons +}; + + +/** + * Handle wimp closing event + * + * \param w The window handle the event occoured on + */ +static void ro_gui_window_close(wimp_w w) +{ + struct gui_window *g; + wimp_pointer pointer; + os_error *error; + char *temp_name; + char *filename = NULL; + struct nsurl *url; + bool destroy; + + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w); + + if (pointer.buttons & wimp_CLICK_ADJUST) { + destroy = !ro_gui_shift_pressed(); + + url = browser_window_get_url(g->bw); + if (url != NULL) { + netsurf_nsurl_to_path(url, &filename); + } + if (filename != NULL) { + temp_name = malloc(strlen(filename) + 32); + if (temp_name) { + char *r; + sprintf(temp_name, "Filer_OpenDir %s", + filename); + r = temp_name + strlen(temp_name); + while (r > temp_name) { + if (*r == '.') { + *r = '\0'; + break; + } + r--; + } + error = xos_cli(temp_name); + if (error) { + LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + return; + } + free(temp_name); + } + free(filename); + } else { + /* this is pointless if we are about to close the + * window */ + if (!destroy && url != NULL) + browser_window_navigate_up(g->bw, false); + } + } else { + destroy = true; + } + + if (destroy) { + browser_window_destroy(g->bw); + } +} + + +/** + * Handle a Redraw_Window_Request for a browser window. + * + * \param redraw The redraw event + */ +static void ro_gui_window_redraw(wimp_draw *redraw) +{ + osbool more; + struct gui_window *g; + os_error *error; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &ro_plotters + }; + + g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w); + + /* We cannot render locked contents. If the browser window is not + * ready for redraw, do nothing. Else, in the case of buffered + * rendering we'll show random data. */ + if (!browser_window_redraw_ready(g->bw)) { + return; + } + + ro_gui_current_redraw_gui = g; + + error = xwimp_redraw_window(redraw, &more); + if (error) { + LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + while (more) { + struct rect clip; + + /* OS's redraw request coordinates are in screen coordinates, + * with an origin at the bottom left of the screen. + * Find the coordinate of the top left of the document in terms + * of OS screen coordinates. + * NOTE: OS units are 2 per px. */ + ro_plot_origin_x = redraw->box.x0 - redraw->xscroll; + ro_plot_origin_y = redraw->box.y1 - redraw->yscroll; + + /* Convert OS redraw rectangle request coordinates into NetSurf + * coordinates. NetSurf coordinates have origin at top left of + * document and units are in px. */ + clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */ + clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */ + clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */ + clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */ + + if (ro_gui_current_redraw_gui->option.buffer_everything) + ro_gui_buffer_open(redraw); + + browser_window_redraw(g->bw, 0, 0, &clip, &ctx); + + if (ro_gui_current_redraw_gui->option.buffer_everything) + ro_gui_buffer_close(); + + /* Check to see if there are more rectangles to draw and + * get next one */ + error = xwimp_get_rectangle(redraw, &more); + /* RISC OS 3.7 returns an error here if enough buffer was + claimed to cause a new dynamic area to be created. It + doesn't actually stop anything working, so we mask it out + for now until a better fix is found. This appears to be a + bug in RISC OS. */ + if (error && !(ro_gui_current_redraw_gui-> + option.buffer_everything && + error->errnum == error_WIMP_GET_RECT)) { + LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + ro_gui_current_redraw_gui = NULL; + return; + } + } + ro_gui_current_redraw_gui = NULL; +} + + +/** + * Process Scroll_Request events in a browser window. + * + * \param scroll The wimp scroll event data block. + */ +static void ro_gui_window_scroll(wimp_scroll *scroll) +{ + struct gui_window *g = ro_gui_window_lookup(scroll->w); + + if (g && browser_window_has_content(g->bw) && ro_gui_shift_pressed()) { + /* extended scroll request with shift held down; change zoom */ + float scale, inc; + + if (scroll->ymin & 3) + inc = 0.02; /* RO5 sends the msg 5 times; + * don't ask me why + * + * @todo this is liable to break if + * HID is configured optimally for + * frame scrolling. *5 appears to be + * an artifact of non-HID mode scrolling. + */ + else + inc = (1 << (ABS(scroll->ymin)>>2)) / 20.0F; + + if (scroll->ymin > 0) { + scale = g->scale + inc; + if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) + scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; + } else { + scale = g->scale - inc; + if (scale < scale_snap_to[0]) + scale = scale_snap_to[0]; + } + if (g->scale != scale) + ro_gui_window_set_scale(g, scale); + } else if (g != NULL) { + ro_gui_window_scroll_action(g, scroll->xmin, scroll->ymin); + } +} + + +/** + * Process Pointer Leaving Window events in a browser window. + * + * These arrive via the termination callback handler from ro_mouse's + * mouse tracking. + * + * \param leaving The wimp pointer leaving event data block. + * \param data The GUI window that the pointer is leaving. + */ +static void ro_gui_window_track_end(wimp_leaving *leaving, void *data) +{ + struct gui_window *g = (struct gui_window *)data; + + if (g != NULL) { + gui_window_set_pointer(g, GUI_POINTER_DEFAULT); + } +} + + +/** + * Process Pointer Entering Window events in a browser window. + * + * \param entering The wimp pointer entering event data block. + */ +static void ro_gui_window_pointer_entering(wimp_entering *entering) +{ + struct gui_window *g = ro_gui_window_lookup(entering->w); + + if (g != NULL) { + ro_mouse_track_start(ro_gui_window_track_end, + ro_gui_window_mouse_at, + g); + } +} + + +/** + * Process Key_Pressed events in a browser window. + * + * \param key The wimp keypress block for the event. + * \return true if the event was handled, else false. + */ +static bool ro_gui_window_keypress(wimp_key *key) +{ + struct gui_window *g; + uint32_t c = (uint32_t) key->c; + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(key->w); + if (g == NULL) { + return false; + } + + /* First send the key to the browser window, eg. form fields. */ + + if ((unsigned)c < 0x20 || + (0x7f <= c && c <= 0x9f) || + (c & IS_WIMP_KEY)) { + /* Munge control keys into unused control chars */ + /* We can't map onto 1->26 (reserved for ctrl+<qwerty> + That leaves 27->31 and 128->159 */ + switch (c & ~IS_WIMP_KEY) { + case wimp_KEY_TAB: + c = 9; + break; + + case wimp_KEY_SHIFT | wimp_KEY_TAB: + c = 11; + break; + + /* cursor movement keys */ + case wimp_KEY_HOME: + case wimp_KEY_CONTROL | wimp_KEY_LEFT: + c = NS_KEY_LINE_START; + break; + + case wimp_KEY_END: + if (os_version >= RISCOS5) { + c = NS_KEY_LINE_END; + } else { + c = NS_KEY_DELETE_RIGHT; + } + break; + + case wimp_KEY_CONTROL | wimp_KEY_RIGHT: + c = NS_KEY_LINE_END; + break; + + case wimp_KEY_CONTROL | wimp_KEY_UP: + c = NS_KEY_TEXT_START; + break; + + case wimp_KEY_CONTROL | wimp_KEY_DOWN: + c = NS_KEY_TEXT_END; + break; + + case wimp_KEY_SHIFT | wimp_KEY_LEFT: + c = NS_KEY_WORD_LEFT ; + break; + + case wimp_KEY_SHIFT | wimp_KEY_RIGHT: + c = NS_KEY_WORD_RIGHT; + break; + + case wimp_KEY_SHIFT | wimp_KEY_UP: + c = NS_KEY_PAGE_UP; + break; + + case wimp_KEY_SHIFT | wimp_KEY_DOWN: + c = NS_KEY_PAGE_DOWN; + break; + + case wimp_KEY_LEFT: + c = NS_KEY_LEFT; + break; + + case wimp_KEY_RIGHT: + c = NS_KEY_RIGHT; + break; + + case wimp_KEY_UP: + c = NS_KEY_UP; + break; + + case wimp_KEY_DOWN: + c = NS_KEY_DOWN; + break; + + /* editing */ + case wimp_KEY_CONTROL | wimp_KEY_END: + c = NS_KEY_DELETE_LINE_END; + break; + + case wimp_KEY_DELETE: + if (ro_gui_ctrl_pressed()) { + c = NS_KEY_DELETE_LINE_START; + } else if (os_version < RISCOS5) { + c = NS_KEY_DELETE_LEFT; + } + break; + + case wimp_KEY_F8: + c = NS_KEY_UNDO; + break; + + case wimp_KEY_F9: + c = NS_KEY_REDO; + break; + + default: + break; + } + } + + if (!(c & IS_WIMP_KEY)) { + if (browser_window_key_press(g->bw, c)) { + return true; + } + } + + return ro_gui_window_handle_local_keypress(g, key, false); +} + + +/** + * Handle Mouse_Click events in a browser window. + * + * This should never see Menu clicks, as these will be routed to the + * menu handlers. + * + * \param pointer details of mouse click + * \return true if click handled, false otherwise + */ +static bool ro_gui_window_click(wimp_pointer *pointer) +{ + struct gui_window *g; + os_coord pos; + + /* We should never see Menu clicks. */ + + if (pointer->buttons == wimp_CLICK_MENU) { + return false; + } + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(pointer->w); + + /* try to close url-completion */ + ro_gui_url_complete_close(); + + /* set input focus */ + if (pointer->buttons & (wimp_SINGLE_SELECT | wimp_SINGLE_ADJUST)) + gui_window_place_caret(g, -100, -100, 0, NULL); + + if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) { + browser_window_mouse_click(g->bw, + ro_gui_mouse_click_state(pointer->buttons, + wimp_BUTTON_DOUBLE_CLICK_DRAG), + pos.x, pos.y); + } + + return true; +} + + +/** + * Prepare or reprepare a form select menu + * + * setting up the menu handle globals in the process. + * + * \param g The RISC OS gui window the menu is in. + * \param control The form control needing a menu. + * \return true if the menu is OK to be opened; else false. + */ +static bool +ro_gui_window_prepare_form_select_menu(struct gui_window *g, + struct form_control *control) +{ + unsigned int item, entries; + char *text_convert, *temp; + struct form_option *option; + bool reopen = true; + nserror err; + + assert(control); + + /* enumerate the entries */ + entries = 0; + option = form_select_get_option(control, entries); + while (option != NULL) { + entries++; + option = form_select_get_option(control, entries); + } + + if (entries == 0) { + /* no menu to display */ + ro_gui_menu_destroy(); + return false; + } + + /* free riscos menu if there already is one */ + if ((gui_form_select_menu) && (control != gui_form_select_control)) { + for (item = 0; ; item++) { + free(gui_form_select_menu->entries[item].data. + indirected_text.text); + if (gui_form_select_menu->entries[item].menu_flags & + wimp_MENU_LAST) + break; + } + free(gui_form_select_menu->title_data.indirected_text.text); + free(gui_form_select_menu); + gui_form_select_menu = 0; + } + + /* allocate new riscos menu */ + if (!gui_form_select_menu) { + reopen = false; + gui_form_select_menu = malloc(wimp_SIZEOF_MENU(entries)); + if (!gui_form_select_menu) { + ro_warn_user("NoMemory", 0); + ro_gui_menu_destroy(); + return false; + } + err = utf8_to_local_encoding(messages_get("SelectMenu"), 0, + &text_convert); + if (err != NSERROR_OK) { + /* badenc should never happen */ + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_local_encoding failed"); + ro_warn_user("NoMemory", 0); + ro_gui_menu_destroy(); + return false; + } + gui_form_select_menu->title_data.indirected_text.text = + text_convert; + ro_gui_menu_init_structure(gui_form_select_menu, entries); + } + + /* initialise menu entries from form control */ + for (item = 0; item < entries; item++) { + option = form_select_get_option(control, item); + gui_form_select_menu->entries[item].menu_flags = 0; + if (option->selected) + gui_form_select_menu->entries[item].menu_flags = + wimp_MENU_TICKED; + if (!reopen) { + + /* convert spaces to hard spaces to stop things + * like 'Go Home' being treated as if 'Home' is a + * keyboard shortcut and right aligned in the menu. + */ + + temp = cnv_space2nbsp(option->text); + if (!temp) { + LOG("cnv_space2nbsp failed"); + ro_warn_user("NoMemory", 0); + ro_gui_menu_destroy(); + return false; + } + + err = utf8_to_local_encoding(temp, + 0, &text_convert); + if (err != NSERROR_OK) { + /* A bad encoding should never happen, + * so assert this */ + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_enc failed"); + ro_warn_user("NoMemory", 0); + ro_gui_menu_destroy(); + return false; + } + + free(temp); + + gui_form_select_menu->entries[item].data.indirected_text.text = + text_convert; + gui_form_select_menu->entries[item].data.indirected_text.size = + strlen(gui_form_select_menu->entries[item]. + data.indirected_text.text) + 1; + } + } + + gui_form_select_menu->entries[0].menu_flags |= + wimp_MENU_TITLE_INDIRECTED; + gui_form_select_menu->entries[item - 1].menu_flags |= wimp_MENU_LAST; + + return true; +} + + +/** + * Return boolean flags to show what RISC OS types we can sensibly convert + * the given object into. + * + * \todo This should probably be somewhere else but in window.c, and + * should probably even be done in content_(). + * + * \param h The object to test. + * \param export_draw true on exit if a drawfile would be possible. + * \param export_sprite true on exit if a sprite would be possible. + * \return true if valid data is returned; else false. + */ +static bool +ro_gui_window_content_export_types(struct hlcache_handle *h, + bool *export_draw, + bool *export_sprite) +{ + bool found_type = false; + + if (export_draw != NULL) { + *export_draw = false; + } + if (export_sprite != NULL) { + *export_sprite = false; + } + + if (h != NULL && content_get_type(h) == CONTENT_IMAGE) { + switch (ro_content_native_type(h)) { + case osfile_TYPE_SPRITE: + /* bitmap types (Sprite export possible) */ + found_type = true; + if (export_sprite != NULL) { + *export_sprite = true; + } + break; + + case osfile_TYPE_DRAW: + /* vector types (Draw export possible) */ + found_type = true; + if (export_draw != NULL) { + *export_draw = true; + } + break; + + default: + break; + } + } + + return found_type; +} + + +/** + * Prepare the browser window menu for (re-)opening + * + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param menu The menu about to be opened. + * \param pointer Pointer to the relevant wimp event block, or + * NULL for an Adjust click. + * \return true if the event was handled; else false. + */ +static bool +ro_gui_window_menu_prepare(wimp_w w, + wimp_i i, + wimp_menu *menu, + wimp_pointer *pointer) { struct gui_window *g; struct browser_window *bw; @@ -2138,13 +2125,13 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, gui_form_select_control); } - if (menu != ro_gui_browser_window_menu) + if (menu != ro_gui_browser_window_menu) { return false; + } /* If this is a new opening for the browser window menu (ie. not for a * toolbar menu), get details of the object under the pointer. */ - if (pointer != NULL && g->window == w) { ro_gui_url_complete_close(); @@ -2255,13 +2242,14 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE_URL_TEXT, current_menu_object == NULL); - if (current_menu_object != NULL) + if (current_menu_object != NULL) { ro_gui_window_content_export_types(current_menu_object, &export_draw, &export_sprite); - else + } else { ro_gui_window_content_export_types( browser_window_get_content(bw), &export_draw, &export_sprite); + } ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_EXPORT, (!have_content && current_menu_object == NULL) @@ -2319,14 +2307,15 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, /* View Submenu */ ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_FOREGROUND, - g != NULL && nsoption_bool(foreground_images)); + g != NULL && nsoption_bool(foreground_images)); ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_BACKGROUND, - g != NULL && nsoption_bool(background_images)); + g != NULL && nsoption_bool(background_images)); ro_gui_menu_set_entry_shaded(menu, BROWSER_BUFFER_ANIMS, g == NULL || g->option.buffer_everything); - ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ANIMS, g != NULL && + ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ANIMS, + g != NULL && (g->option.buffer_animations || g->option.buffer_everything)); @@ -2337,16 +2326,16 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, ro_gui_menu_set_entry_shaded(menu, BROWSER_SCALE_VIEW, !have_content); ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_STAGGER, - nsoption_int(window_screen_width) == 0); + nsoption_int(window_screen_width) == 0); ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_STAGGER, - ((nsoption_int(window_screen_width) == 0) || - nsoption_bool(window_stagger))); + ((nsoption_int(window_screen_width) == 0) || + nsoption_bool(window_stagger))); ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_COPY, - nsoption_bool(window_size_clone)); + nsoption_bool(window_size_clone)); ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_RESET, - nsoption_int(window_screen_width) == 0); + nsoption_int(window_screen_width) == 0); /* Utilities Submenu */ @@ -2370,199 +2359,72 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, /** - * Handle submenu warnings for a browser window menu + * Process selections from a form select menu, passing them back to the core. * - * \param w The window owning the menu. - * \param i The icon owning the menu. - * \param *menu The menu to which the warning applies. - * \param *selection The wimp menu selection data. - * \param action The selected menu action. + * \param g The browser window affected by the menu. + * \param selection The menu selection. */ - -void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action) +static void +ro_gui_window_process_form_select_menu(struct gui_window *g, + wimp_selection *selection) { - struct gui_window *g; - struct hlcache_handle *h; - bool export; - - if (menu != ro_gui_browser_window_menu) - return; - - g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w); - h = browser_window_get_content(g->bw); - - switch (action) { - case BROWSER_PAGE_INFO: - if (h != NULL) - ro_gui_window_prepare_pageinfo(g); - break; - - case BROWSER_FIND_TEXT: - if (h != NULL && (content_get_type(h) == CONTENT_HTML || - content_get_type(h) == CONTENT_TEXTPLAIN)) - ro_gui_search_prepare(g->bw); - break; - - case BROWSER_SCALE_VIEW: - if (h != NULL) - ro_gui_dialog_prepare_zoom(g); - break; - - case BROWSER_PRINT: - if (h != NULL) - ro_gui_print_prepare(g); - break; - - case BROWSER_OBJECT_INFO: - if (current_menu_object != NULL) - ro_gui_window_prepare_objectinfo(current_menu_object, - current_menu_url); - break; - - case BROWSER_OBJECT_SAVE: - if (current_menu_object != NULL) - ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, - current_menu_object, NULL, NULL, NULL); - break; - - case BROWSER_SELECTION_SAVE: - if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY) - ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, - browser_window_get_selection(g->bw), - NULL, NULL); - break; - - case BROWSER_SAVE_URL_URI: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, - hlcache_handle_get_url(h), - content_get_title(h)); - break; - - case BROWSER_SAVE_URL_URL: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, - hlcache_handle_get_url(h), - content_get_title(h)); - break; - - case BROWSER_SAVE_URL_TEXT: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, - hlcache_handle_get_url(h), - content_get_title(h)); - break; - - case BROWSER_OBJECT_SAVE_URL_URI: - if (current_menu_object != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, - hlcache_handle_get_url( - current_menu_object), - content_get_title(current_menu_object)); - break; - - case BROWSER_OBJECT_SAVE_URL_URL: - if (current_menu_object != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, - hlcache_handle_get_url( - current_menu_object), - content_get_title(current_menu_object)); - break; - - case BROWSER_OBJECT_SAVE_URL_TEXT: - if (current_menu_object != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, - hlcache_handle_get_url( - current_menu_object), - content_get_title(current_menu_object)); - break; - - case BROWSER_SAVE: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL); - break; - - case BROWSER_SAVE_COMPLETE: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL); - break; - - case BROWSER_EXPORT_DRAW: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL); - break; - - case BROWSER_EXPORT_PDF: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL); - break; - - case BROWSER_EXPORT_TEXT: - if (h != NULL) - ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL); - break; - - case BROWSER_LINK_SAVE_URI: - if (current_menu_url != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, - current_menu_url, NULL); - break; - - case BROWSER_LINK_SAVE_URL: - if (current_menu_url != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, - current_menu_url, NULL); - break; + assert(g != NULL); - case BROWSER_LINK_SAVE_TEXT: - if (current_menu_url != NULL) - ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, - current_menu_url, NULL); - break; + if (selection->items[0] >= 0) { + form_select_process_selection(gui_form_select_control, + selection->items[0]); + } +} - case BROWSER_OBJECT_EXPORT_SPRITE: - if (current_menu_object != NULL) { - ro_gui_window_content_export_types(current_menu_object, - NULL, &export); - if (export) - ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - current_menu_object, - NULL, NULL, NULL); - } else if (h != NULL) { - ro_gui_window_content_export_types(h, NULL, &export); +/** + * Prepare the object info window for use + * + * \param object the object for which information is to be displayed + * \param target_url corresponding url, if any + */ +static void +ro_gui_window_prepare_objectinfo(struct hlcache_handle *object, + nsurl *target_url) +{ + char icon_buf[20] = "file_xxx"; + const char *url; + lwc_string *mime; + const char *target = "-"; - if (export) - ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - h, NULL, NULL, NULL); - } - break; + sprintf(icon_buf, "file_%.3x",ro_content_filetype(object)); + if (!ro_gui_wimp_sprite_exists(icon_buf)) { + sprintf(icon_buf, "file_xxx"); + } - case BROWSER_OBJECT_EXPORT_DRAW: - if (current_menu_object != NULL) { - ro_gui_window_content_export_types(current_menu_object, - &export, NULL); + url = nsurl_access(hlcache_handle_get_url(object)); + if (url == NULL) { + url = "-"; + } + mime = content_get_mime_type(object); - if (export) - ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - current_menu_object, - NULL, NULL, NULL); - } else if (h != NULL) { - ro_gui_window_content_export_types(h, &export, NULL); + if (target_url != NULL) { + target = nsurl_access(target_url); + } - if (export) - ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - h, NULL, NULL, NULL); - } - break; + ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_ICON, + icon_buf, true); + ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_URL, + url, true); + ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TARGET, + target, true); + ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TYPE, + lwc_string_data(mime), true); - default: - break; - } + lwc_string_unref(mime); } +/** + * callback to handle window paste operation + * + * \param pw context containing browser window + */ static void ro_gui_window_paste_cb(void *pw) { struct browser_window *bw = pw; @@ -2574,22 +2436,25 @@ static void ro_gui_window_paste_cb(void *pw) /** * Handle selections from a browser window menu * - * \param w The window owning the menu. - * \param i The icon owning the menu. - * \param *menu The menu from which the selection was made. - * \param *selection The wimp menu selection data. - * \param action The selected menu action. - * \return true if action accepted; else false. + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param menu The menu from which the selection was made. + * \param selection The wimp menu selection data. + * \param action The selected menu action. + * \return true if action accepted; else false. */ - -bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action) +static bool +ro_gui_window_menu_select(wimp_w w, + wimp_i i, + wimp_menu *menu, + wimp_selection *selection, + menu_action action) { - struct gui_window *g; - struct browser_window *bw; - struct hlcache_handle *h; - struct toolbar *toolbar; - wimp_window_state state; + struct gui_window *g; + struct browser_window *bw; + struct hlcache_handle *h; + struct toolbar *toolbar; + wimp_window_state state; nsurl *url; nserror error = NSERROR_OK; @@ -2601,7 +2466,6 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, /* If this is a form menu from the core, handle it now and then exit. * Otherwise, carry on to the main browser window menu. */ - if (menu == gui_form_select_menu && w == g->window) { ro_gui_window_process_form_select_menu(g, selection); @@ -2619,10 +2483,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, error = nsurl_create("http://www.netsurf-browser.org/documentation/", &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); + url, + NULL, + NULL, + NULL); nsurl_unref(url); } break; @@ -2631,10 +2495,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, error = nsurl_create("http://www.netsurf-browser.org/documentation/guide", &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); + url, + NULL, + NULL, + NULL); nsurl_unref(url); } break; @@ -2643,10 +2507,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, error = nsurl_create("http://www.netsurf-browser.org/documentation/info", &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); + url, + NULL, + NULL, + NULL); nsurl_unref(url); } break; @@ -2655,10 +2519,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, error = nsurl_create("about:credits", &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); + url, + NULL, + NULL, + NULL); nsurl_unref(url); } break; @@ -2667,10 +2531,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, error = nsurl_create("about:licence", &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); + url, + NULL, + NULL, + NULL); nsurl_unref(url); } break; @@ -2680,7 +2544,8 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, ro_gui_interactive_help_start(); nsoption_set_bool(interactive_help, true); } else { - nsoption_set_bool(interactive_help, !nsoption_bool(interactive_help)); + nsoption_set_bool(interactive_help, + !nsoption_bool(interactive_help)); } break; @@ -2732,9 +2597,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, case BROWSER_OBJECT_INFO: if (current_menu_object != NULL) { ro_gui_window_prepare_objectinfo(current_menu_object, - current_menu_url); + current_menu_url); ro_gui_dialog_open_persistent(g->window, - dialog_objinfo, false); + dialog_objinfo, + false); } break; case BROWSER_OBJECT_RELOAD: @@ -2747,50 +2613,62 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, /* link actions */ case BROWSER_LINK_SAVE_URI: if (current_menu_url != NULL) { - ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, - current_menu_url, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + ro_gui_save_prepare(GUI_SAVE_LINK_URI, + NULL, + NULL, + current_menu_url, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; case BROWSER_LINK_SAVE_URL: if (current_menu_url != NULL) { - ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, - current_menu_url, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + ro_gui_save_prepare(GUI_SAVE_LINK_URL, + NULL, + NULL, + current_menu_url, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; case BROWSER_LINK_SAVE_TEXT: if (current_menu_url != NULL) { - ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, - current_menu_url, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, + NULL, + NULL, + current_menu_url, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; case BROWSER_LINK_DOWNLOAD: if (current_menu_url != NULL) { - error = browser_window_navigate(bw, - current_menu_url, - browser_window_get_url(bw), - BW_NAVIGATE_DOWNLOAD, - NULL, - NULL, - NULL); + error = browser_window_navigate( + bw, + current_menu_url, + browser_window_get_url(bw), + BW_NAVIGATE_DOWNLOAD, + NULL, + NULL, + NULL); } break; case BROWSER_LINK_NEW_WINDOW: if (current_menu_url != NULL) { error = browser_window_create( - BW_CREATE_HISTORY | - BW_CREATE_CLONE, - current_menu_url, - browser_window_get_url(bw), - bw, - NULL); + BW_CREATE_HISTORY | BW_CREATE_CLONE, + current_menu_url, + browser_window_get_url(bw), + bw, + NULL); } break; @@ -2799,24 +2677,36 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, case BROWSER_OBJECT_SAVE: if (current_menu_object != NULL) { ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, - current_menu_object, NULL, NULL, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + current_menu_object, + NULL, + NULL, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; case BROWSER_OBJECT_EXPORT_SPRITE: if (current_menu_object != NULL) { ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - current_menu_object, NULL, NULL, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + current_menu_object, + NULL, + NULL, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; case BROWSER_OBJECT_EXPORT_DRAW: if (current_menu_object != NULL) { ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, - current_menu_object, NULL, NULL, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + current_menu_object, + NULL, + NULL, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; @@ -2848,10 +2738,13 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, /* selection actions */ case BROWSER_SELECTION_SAVE: if (h != NULL) { - ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, + ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, + NULL, browser_window_get_selection(bw), - NULL, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, + NULL, + NULL); + ro_gui_dialog_open_persistent(g->window, + dialog_saveas, false); } break; @@ -2970,19 +2863,19 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, case TOOLBAR_BUTTONS: assert(toolbar); ro_toolbar_set_display_buttons(toolbar, - !ro_toolbar_get_display_buttons(toolbar)); + !ro_toolbar_get_display_buttons(toolbar)); break; case TOOLBAR_ADDRESS_BAR: assert(toolbar); ro_toolbar_set_display_url(toolbar, - !ro_toolbar_get_display_url(toolbar)); + !ro_toolbar_get_display_url(toolbar)); if (ro_toolbar_get_display_url(toolbar)) ro_toolbar_take_caret(toolbar); break; case TOOLBAR_THROBBER: assert(toolbar); ro_toolbar_set_display_throbber(toolbar, - !ro_toolbar_get_display_throbber(toolbar)); + !ro_toolbar_get_display_throbber(toolbar)); break; case TOOLBAR_EDIT: assert(toolbar); @@ -3002,467 +2895,875 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, /** - * Handle the closure of a browser window menu + * Handle submenu warnings for a browser window menu * - * \param w The window owning the menu. - * \param i The icon owning the menu. - * \param *menu The menu that is being closed. + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param menu The menu to which the warning applies. + * \param selection The wimp menu selection data. + * \param action The selected menu action. */ - -void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu) +static void +ro_gui_window_menu_warning(wimp_w w, + wimp_i i, + wimp_menu *menu, + wimp_selection *selection, + menu_action action) { - if (menu == ro_gui_browser_window_menu) { - current_menu_object = NULL; - current_menu_url = NULL; - } else if (menu == gui_form_select_menu) { - gui_form_select_control = NULL; + struct gui_window *g; + struct hlcache_handle *h; + bool export; + + if (menu != ro_gui_browser_window_menu) { + return; } -} + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w); + h = browser_window_get_content(g->bw); -/** - * Process Scroll_Request events in a browser window. - * - * \param *scroll The wimp scroll event data block. - */ + switch (action) { + case BROWSER_PAGE_INFO: + if (h != NULL) { + ro_gui_window_prepare_pageinfo(g); + } + break; -void ro_gui_window_scroll(wimp_scroll *scroll) -{ - struct gui_window *g = ro_gui_window_lookup(scroll->w); + case BROWSER_FIND_TEXT: + if (h != NULL && + (content_get_type(h) == CONTENT_HTML || + content_get_type(h) == CONTENT_TEXTPLAIN)) { + ro_gui_search_prepare(g->bw); + } + break; - if (g && browser_window_has_content(g->bw) && ro_gui_shift_pressed()) { - /* extended scroll request with shift held down; change zoom */ - float scale, inc; + case BROWSER_SCALE_VIEW: + if (h != NULL) { + ro_gui_dialog_prepare_zoom(g); + } + break; - if (scroll->ymin & 3) - inc = 0.02; /* RO5 sends the msg 5 times; - * don't ask me why - * - * @todo this is liable to break if - * HID is configured optimally for - * frame scrolling. *5 appears to be - * an artifact of non-HID mode scrolling. - */ - else - inc = (1 << (ABS(scroll->ymin)>>2)) / 20.0F; + case BROWSER_PRINT: + if (h != NULL) { + ro_gui_print_prepare(g); + } + break; - if (scroll->ymin > 0) { - scale = g->scale + inc; - if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) - scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; - } else { - scale = g->scale - inc; - if (scale < scale_snap_to[0]) - scale = scale_snap_to[0]; + case BROWSER_OBJECT_INFO: + if (current_menu_object != NULL) { + ro_gui_window_prepare_objectinfo(current_menu_object, + current_menu_url); } - if (g->scale != scale) - ro_gui_window_set_scale(g, scale); - } else if (g != NULL) { - ro_gui_window_scroll_action(g, scroll->xmin, scroll->ymin); + break; + + case BROWSER_OBJECT_SAVE: + if (current_menu_object != NULL) { + ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, + current_menu_object, + NULL, + NULL, + NULL); + } + break; + + case BROWSER_SELECTION_SAVE: + if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY) + ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, + browser_window_get_selection(g->bw), + NULL, NULL); + break; + + case BROWSER_SAVE_URL_URI: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + hlcache_handle_get_url(h), + content_get_title(h)); + break; + + case BROWSER_SAVE_URL_URL: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + hlcache_handle_get_url(h), + content_get_title(h)); + break; + + case BROWSER_SAVE_URL_TEXT: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + hlcache_handle_get_url(h), + content_get_title(h)); + break; + + case BROWSER_OBJECT_SAVE_URL_URI: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + hlcache_handle_get_url( + current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_OBJECT_SAVE_URL_URL: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + hlcache_handle_get_url( + current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_OBJECT_SAVE_URL_TEXT: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + hlcache_handle_get_url( + current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_SAVE: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL); + break; + + case BROWSER_SAVE_COMPLETE: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_DRAW: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_PDF: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_TEXT: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL); + break; + + case BROWSER_LINK_SAVE_URI: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_LINK_SAVE_URL: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_LINK_SAVE_TEXT: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_OBJECT_EXPORT_SPRITE: + if (current_menu_object != NULL) { + ro_gui_window_content_export_types(current_menu_object, + NULL, &export); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, + NULL, NULL, NULL); + } else if (h != NULL) { + ro_gui_window_content_export_types(h, NULL, &export); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + h, NULL, NULL, NULL); + } + break; + + case BROWSER_OBJECT_EXPORT_DRAW: + if (current_menu_object != NULL) { + ro_gui_window_content_export_types(current_menu_object, + &export, NULL); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, + NULL, NULL, NULL); + } else if (h != NULL) { + ro_gui_window_content_export_types(h, &export, NULL); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + h, NULL, NULL, NULL); + } + break; + + default: + break; } } + /** - * Process Pointer Entering Window events in a browser window. + * Handle the closure of a browser window menu * - * \param *entering The wimp pointer entering event data block. + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param menu The menu that is being closed. */ - -static void ro_gui_window_pointer_entering(wimp_entering *entering) +static void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu) { - struct gui_window *g = ro_gui_window_lookup(entering->w); - - if (g != NULL) - ro_mouse_track_start(ro_gui_window_track_end, - ro_gui_window_mouse_at, g); + if (menu == ro_gui_browser_window_menu) { + current_menu_object = NULL; + current_menu_url = NULL; + } else if (menu == gui_form_select_menu) { + gui_form_select_control = NULL; + } } + /** - * Process Pointer Leaving Window events in a browser window. These arrive via - * the termination callback handler from ro_mouse's mouse tracking. + * Clones a browser window's options. * - * \param *leaving The wimp pointer leaving event data block. - * \param *data The GUI window that the pointer is leaving. + * \param new_gui the new gui window + * \param old_gui the gui window to clone from, or NULL for default */ - -static void ro_gui_window_track_end(wimp_leaving *leaving, void *data) +static void +ro_gui_window_clone_options(struct gui_window *new_gui, + struct gui_window *old_gui) { - struct gui_window *g = (struct gui_window *) data; + assert(new_gui); - if (g != NULL) - gui_window_set_pointer(g, GUI_POINTER_DEFAULT); + /* Clone the basic options + */ + if (!old_gui) { + new_gui->option.buffer_animations = nsoption_bool(buffer_animations); + new_gui->option.buffer_everything = nsoption_bool(buffer_everything); + } else { + new_gui->option = old_gui->option; + } + + /* Set up the toolbar + */ + if (new_gui->toolbar) { + ro_toolbar_set_display_buttons(new_gui->toolbar, + nsoption_bool(toolbar_show_buttons)); + ro_toolbar_set_display_url(new_gui->toolbar, + nsoption_bool(toolbar_show_address)); + ro_toolbar_set_display_throbber(new_gui->toolbar, + nsoption_bool(toolbar_show_throbber)); + if ((old_gui) && (old_gui->toolbar)) { + ro_toolbar_set_display_buttons(new_gui->toolbar, + ro_toolbar_get_display_buttons( + old_gui->toolbar)); + ro_toolbar_set_display_url(new_gui->toolbar, + ro_toolbar_get_display_url( + old_gui->toolbar)); + ro_toolbar_set_display_throbber(new_gui->toolbar, + ro_toolbar_get_display_throbber( + old_gui->toolbar)); + ro_toolbar_process(new_gui->toolbar, -1, true); + } + } } /** - * Scroll a browser window, either via the core or directly using the - * normal Wimp_OpenWindow interface. - * - * Scroll steps are supplied in terms of the (extended) Scroll Event direction - * values returned by Wimp_Poll. Special values of 0x7fffffff and 0x80000000 - * are added to mean "Home" and "End". + * Create and open a new browser window. * - * \param *g The GUI Window to be scrolled. - * \param scroll_x The X scroll step to be applied. - * \param scroll_y The Y scroll step to be applied. + * \param bw bw to create gui_window for + * \param existing an existing gui_window, may be NULL + * \param flags flags for gui window creation + * \return gui window, or NULL on error */ - -void ro_gui_window_scroll_action(struct gui_window *g, - wimp_scroll_direction scroll_x, wimp_scroll_direction scroll_y) +static struct gui_window *gui_window_create(struct browser_window *bw, + struct gui_window *existing, + gui_window_create_flags flags) { - int visible_x, visible_y; - int step_x = 0, step_y = 0; - int toolbar_y; - wimp_window_state state; - wimp_pointer pointer; - os_error *error; - os_coord pos; - bool handled = false; - struct toolbar *toolbar; + int screen_width, screen_height; + static int window_count = 2; + wimp_window window; + wimp_window_state state; + os_error *error; + bool open_centred = true; + struct gui_window *g; - if (g == NULL) - return; + g = malloc(sizeof *g); + if (!g) { + ro_warn_user("NoMemory", 0); + return 0; + } + g->bw = bw; + g->toolbar = 0; + g->status_bar = 0; + g->old_width = 0; + g->old_height = 0; + g->update_extent = true; + g->active = false; + strcpy(g->title, "NetSurf"); + g->iconise_icon = -1; + g->scale = browser_window_get_scale(bw); - /* Get the current window, toolbar and pointer details. */ + /* Set the window position */ + if (existing != NULL && + flags & GW_CREATE_CLONE && + nsoption_bool(window_size_clone)) { + state.w = existing->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + window.visible.x0 = state.visible.x0; + window.visible.x1 = state.visible.x1; + window.visible.y0 = state.visible.y0 - 48; + window.visible.y1 = state.visible.y1 - 48; + open_centred = false; + } else { + int win_width, win_height; + ro_gui_screen_size(&screen_width, &screen_height); - state.w = g->window; - error = xwimp_get_window_state(&state); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - return; + /* Check if we have a preferred position */ + if ((nsoption_int(window_screen_width) != 0) && + (nsoption_int(window_screen_height) != 0)) { + win_width = (nsoption_int(window_width) * + screen_width) / + nsoption_int(window_screen_width); + win_height = (nsoption_int(window_height) * + screen_height) / + nsoption_int(window_screen_height); + window.visible.x0 = (nsoption_int(window_x) * + screen_width) / + nsoption_int(window_screen_width); + window.visible.y0 = (nsoption_int(window_y) * + screen_height) / + nsoption_int(window_screen_height); + if (nsoption_bool(window_stagger)) { + window.visible.y0 += 96 - + (48 * (window_count % 5)); + } + open_centred = false; + if (win_width < 100) + win_width = 100; + if (win_height < 100) + win_height = 100; + } else { + + /* Base how we define the window height/width + on the compile time options set */ + win_width = screen_width * 3 / 4; + if (1600 < win_width) + win_width = 1600; + win_height = win_width * 3 / 4; + + window.visible.x0 = (screen_width - win_width) / 2; + window.visible.y0 = ((screen_height - win_height) / 2) + + 96 - (48 * (window_count % 5)); + } + window.visible.x1 = window.visible.x0 + win_width; + window.visible.y1 = window.visible.y0 + win_height; } - toolbar = ro_toolbar_parent_window_lookup(g->window); - assert(g == NULL || g->toolbar == NULL || g->toolbar == toolbar); + /* General flags for a non-movable, non-resizable, no-title bar window */ + window.xscroll = 0; + window.yscroll = 0; + window.next = wimp_TOP; + window.flags = wimp_WINDOW_MOVEABLE | + wimp_WINDOW_NEW_FORMAT | + wimp_WINDOW_VSCROLL | + wimp_WINDOW_HSCROLL | + wimp_WINDOW_IGNORE_XEXTENT | + wimp_WINDOW_IGNORE_YEXTENT | + wimp_WINDOW_SCROLL_REPEAT; + window.title_fg = wimp_COLOUR_BLACK; + window.title_bg = wimp_COLOUR_LIGHT_GREY; + window.work_fg = wimp_COLOUR_LIGHT_GREY; + window.work_bg = wimp_COLOUR_TRANSPARENT; + window.scroll_outer = wimp_COLOUR_DARK_GREY; + window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY; + window.highlight_bg = wimp_COLOUR_CREAM; + window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST | + wimp_WINDOW_GIVE_SHADED_ICON_INFO; + window.extent.x0 = 0; + window.extent.y0 = -(window.visible.y1 - window.visible.y0); + window.extent.x1 = window.visible.x1 - window.visible.x0; + window.extent.y1 = 0; + window.title_flags = wimp_ICON_TEXT | + wimp_ICON_INDIRECTED | + wimp_ICON_HCENTRED; + window.work_flags = wimp_BUTTON_DOUBLE_CLICK_DRAG << + wimp_ICON_BUTTON_TYPE_SHIFT; + window.sprite_area = wimpspriteop_AREA; + window.xmin = 1; + window.ymin = 1; + window.title_data.indirected_text.text = g->title; + window.title_data.indirected_text.validation = (char *) -1; + window.title_data.indirected_text.size = 255; + window.icon_count = 0; - toolbar_y = (toolbar == NULL) ? 0 : ro_toolbar_full_height(toolbar); + /* Add in flags */ + window.flags |= wimp_WINDOW_SIZE_ICON | + wimp_WINDOW_BACK_ICON | + wimp_WINDOW_CLOSE_ICON | + wimp_WINDOW_TITLE_ICON | + wimp_WINDOW_TOGGLE_ICON; - visible_x = state.visible.x1 - state.visible.x0 - 32; - visible_y = state.visible.y1 - state.visible.y0 - 32 - toolbar_y; + if (open_centred) { + int scroll_width = ro_get_vscroll_width(NULL); + window.visible.x0 -= scroll_width; + } - error = xwimp_get_pointer_info(&pointer); + error = xwimp_create_window(&window, &g->window); if (error) { - LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); + LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); - return; + free(g); + return 0; } - /* Turn the scroll requirement from Scroll Event codes into coordinates - * that the core can understand. - */ + /* Link into window list */ + g->prev = 0; + g->next = window_list; + if (window_list) + window_list->prev = g; + window_list = g; + window_count++; - switch (scroll_x) { - case wimp_SCROLL_PAGE_LEFT: - step_x = SCROLL_PAGE_DOWN; - break; - case wimp_SCROLL_AUTO_LEFT: - case wimp_SCROLL_COLUMN_LEFT: - step_x = -16; - break; - case wimp_SCROLL_AUTO_RIGHT: - case wimp_SCROLL_COLUMN_RIGHT: - step_x = 16; - break; - case wimp_SCROLL_PAGE_RIGHT: - step_x = SCROLL_PAGE_UP; - break; - case 0x80000000: - step_x = SCROLL_BOTTOM; - break; - case 0x7fffffff: - step_x = SCROLL_TOP; - break; - default: - step_x = (visible_x * (scroll_x>>2)) >> 2; - break; + /* Add in a toolbar and status bar */ + g->status_bar = ro_gui_status_bar_create(g->window, + nsoption_int(toolbar_status_size)); + g->toolbar = ro_toolbar_create(NULL, g->window, + THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE, + &ro_gui_window_toolbar_callbacks, g, + "HelpToolbar"); + if (g->toolbar != NULL) { + ro_toolbar_add_buttons(g->toolbar, + brower_toolbar_buttons, + nsoption_charp(toolbar_browser)); + ro_toolbar_add_url(g->toolbar); + ro_toolbar_add_throbber(g->toolbar); + ro_toolbar_rebuild(g->toolbar); } - switch (scroll_y) { - case wimp_SCROLL_PAGE_UP: - step_y = SCROLL_PAGE_UP; - break; - case wimp_SCROLL_AUTO_UP: - case wimp_SCROLL_LINE_UP: - step_y = -16; - break; - case wimp_SCROLL_AUTO_DOWN: - case wimp_SCROLL_LINE_DOWN: - step_y = 16; - break; - case wimp_SCROLL_PAGE_DOWN: - step_y = SCROLL_PAGE_DOWN; - break; - case 0x80000000: - step_y = SCROLL_BOTTOM; - break; - case 0x7fffffff: - step_y = SCROLL_TOP; - break; - default: - step_y = -((visible_y * (scroll_y>>2)) >> 2); - break; - } + /* Register event handlers. Do this quickly, as some of the things + * that follow will indirectly look up our user data: this MUST + * be set first! + */ + ro_gui_wimp_event_set_user_data(g->window, g); + ro_gui_wimp_event_register_open_window(g->window, + ro_gui_window_open); + ro_gui_wimp_event_register_close_window(g->window, + ro_gui_window_close); + ro_gui_wimp_event_register_redraw_window(g->window, + ro_gui_window_redraw); + ro_gui_wimp_event_register_scroll_window(g->window, + ro_gui_window_scroll); + ro_gui_wimp_event_register_pointer_entering_window(g->window, + ro_gui_window_pointer_entering); + ro_gui_wimp_event_register_keypress(g->window, + ro_gui_window_keypress); + ro_gui_wimp_event_register_mouse_click(g->window, + ro_gui_window_click); + ro_gui_wimp_event_register_menu(g->window, + ro_gui_browser_window_menu, + true, false); + ro_gui_wimp_event_register_menu_prepare(g->window, + ro_gui_window_menu_prepare); + ro_gui_wimp_event_register_menu_selection(g->window, + ro_gui_window_menu_select); + ro_gui_wimp_event_register_menu_warning(g->window, + ro_gui_window_menu_warning); + ro_gui_wimp_event_register_menu_close(g->window, + ro_gui_window_menu_close); - /* If no scrolling is required, there's no point trying to do any. */ + /* Set the window options */ + ro_gui_window_clone_options(g, existing); + ro_gui_window_update_toolbar_buttons(g); - if (step_x == 0 && step_y == 0) - return; + /* Open the window at the top of the stack */ + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return g; + } - /* If the pointer is over the window being scrolled, then try to get - * the core to do the scrolling on the object under the pointer. - */ + state.next = wimp_TOP; - if (pointer.w == g->window && - ro_gui_window_to_window_pos(g, - pointer.pos.x, pointer.pos.y, &pos)) - handled = browser_window_scroll_at_point(g->bw, pos.x, pos.y, - step_x, step_y); + ro_gui_window_open(PTR_WIMP_OPEN(&state)); - /* If the core didn't do the scrolling, handle it via the Wimp. - * Windows which contain frames can only be scrolled by the core, - * because it implements frame scroll bars. - */ + /* Claim the caret */ + if (ro_toolbar_take_caret(g->toolbar)) { + ro_gui_url_complete_start(g->toolbar); + } else { + gui_window_place_caret(g, -100, -100, 0, NULL); + } - if (!handled && (browser_window_is_frameset(g->bw) == false)) { - switch (step_x) { - case SCROLL_TOP: - state.xscroll -= 0x10000000; - break; - case SCROLL_BOTTOM: - state.xscroll += 0x10000000; - break; - case SCROLL_PAGE_UP: - state.xscroll += visible_x; - break; - case SCROLL_PAGE_DOWN: - state.xscroll -= visible_x; - break; - default: - state.xscroll += 2 * step_x; - break; - } + return g; +} - switch (step_y) { - case SCROLL_TOP: - state.yscroll += 0x10000000; - break; - case SCROLL_BOTTOM: - state.yscroll -= 0x10000000; - break; - case SCROLL_PAGE_UP: - state.yscroll += visible_y; - break; - case SCROLL_PAGE_DOWN: - state.yscroll -= visible_y; - break; - default: - state.yscroll -= 2 * step_y; - break; - } - error = xwimp_open_window((wimp_open *) &state); - if (error) { - LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); +/** + * Remove all pending update boxes for a window + * + * \param g gui_window + */ +static void ro_gui_window_remove_update_boxes(struct gui_window *g) +{ + struct update_box *cur; + + for (cur = pending_updates; cur != NULL; cur = cur->next) { + if (cur->g == g) { + cur->g = NULL; } } } /** - * Handle Message_DataLoad (file dragged in) for a window. - * - * \param g window - * \param message Message_DataLoad block - * \return true if the load was processed + * Close a browser window and free any related resources. * - * If the file was dragged into a form file input, it is used as the value. + * \param g gui_window to destroy */ - -bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) +static void gui_window_destroy(struct gui_window *g) { os_error *error; - os_coord pos; + wimp_w w; - /* Ignore directories etc. */ - if (0x1000 <= message->data.data_xfer.file_type) - return false; + assert(g); - if (!ro_gui_window_to_window_pos(g, message->data.data_xfer.pos.x, - message->data.data_xfer.pos.y, &pos)) - return false; + /* stop any tracking */ + ro_mouse_kill(g); - if (browser_window_drop_file_at_point(g->bw, pos.x, pos.y, - message->data.data_xfer.file_name) == false) - return false; + /* remove from list */ + if (g->prev) + g->prev->next = g->next; + else + window_list = g->next; + if (g->next) + g->next->prev = g->prev; - /* send DataLoadAck */ - message->action = message_DATA_LOAD_ACK; - message->your_ref = message->my_ref; - error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender); + /* destroy toolbar */ + if (g->toolbar) + ro_toolbar_destroy(g->toolbar); + if (g->status_bar) + ro_gui_status_bar_destroy(g->status_bar); + + w = g->window; + ro_gui_url_complete_close(); + ro_gui_dialog_close_persistent(w); + if (current_menu_window == w) + ro_gui_menu_destroy(); + ro_gui_window_remove_update_boxes(g); + + /* delete window */ + error = xwimp_delete_window(w); if (error) { - LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess); + LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); } + ro_gui_wimp_event_finalise(w); - return true; + free(g); } /** - * Handle pointer movements in a browser window. + * Set the title of a browser window. * - * \param *pointer new mouse position - * \param *data browser window that the pointer is in + * \param g gui_window to update + * \param title new window title, copied */ - -void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data) +static void gui_window_set_title(struct gui_window *g, const char *title) { - os_coord pos; - struct gui_window *g = (struct gui_window *) data; + assert(g); + assert(title); - if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) - browser_window_mouse_track(g->bw, - ro_gui_mouse_drag_state(pointer->buttons, - wimp_BUTTON_DOUBLE_CLICK_DRAG), - pos.x, pos.y); + if (g->scale != 1.0) { + int scale_disp = g->scale * 100; + + if (ABS((float)scale_disp - g->scale * 100) >= 0.05) + snprintf(g->title, sizeof g->title, "%s (%.1f%%)", + title, g->scale * 100); + else + snprintf(g->title, sizeof g->title, "%s (%i%%)", + title, scale_disp); + } else { + strncpy(g->title, title, sizeof g->title); + } + + ro_gui_set_window_title(g->window, g->title); } /** - * Window is being iconised. Create a suitable thumbnail sprite - * (which, sadly, must be in the Wimp sprite pool), and return - * the sprite name and truncated title to the iconiser + * Get the scroll position of a browser window. * - * \param g the gui window being iconised - * \param wi the WindowInfo message from the iconiser + * \param g gui_window + * \param sx receives x ordinate of point at top-left of window + * \param sy receives y ordinate of point at top-left of window + * \return true iff successful */ +static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) +{ + wimp_window_state state; + os_error *error; + int toolbar_height = 0; + + assert(g); + + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } -void ro_gui_window_iconise(struct gui_window *g, - wimp_full_message_window_info *wi) + if (g->toolbar) + toolbar_height = ro_toolbar_full_height(g->toolbar); + *sx = state.xscroll / (2 * g->scale); + *sy = -(state.yscroll - toolbar_height) / (2 * g->scale); + return true; +} + + +/** + * Set the scroll position of a riscos browser window. + * + * Scrolls the viewport to ensure the specified rectangle of the + * content is shown. + * + * \param g gui window to scroll + * \param rect The rectangle to ensure is shown. + * \return NSERROR_OK on success or apropriate error code. + */ +static nserror +gui_window_set_scroll(struct gui_window *g, const struct rect *rect) { - /* sadly there is no 'legal' way to get the sprite into - * the Wimp sprite pool other than via a filing system */ - const char *temp_fname = "Pipe:$._tmpfile"; - struct browser_window *bw = g->bw; - osspriteop_header *overlay = NULL; - osspriteop_header *sprite_header; - struct bitmap *bitmap; - osspriteop_area *area; - int width = 34, height = 34; - struct hlcache_handle *h; + wimp_window_state state; os_error *error; - int len, id; + int toolbar_height = 0; - assert(bw); + assert(g); - h = browser_window_get_content(bw); - if (!h) return; + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return NSERROR_BAD_PARAMETER; + } - /* if an overlay sprite is defined, locate it and gets its dimensions - * so that we can produce a thumbnail with the same dimensions */ - if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { - error = xosspriteop_read_sprite_info(osspriteop_PTR, - (osspriteop_area *)0x100, - (osspriteop_id)overlay, &width, &height, NULL, - NULL); - if (error) { - LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("MiscError", error->errmess); - overlay = NULL; + if (g->toolbar) { + toolbar_height = ro_toolbar_full_height(g->toolbar); + } + + if ((rect->x0 == rect->x1) && (rect->y0 == rect->y1)) { + /* scroll to top */ + state.xscroll = rect->x0 * 2 * g->scale; + state.yscroll = (-rect->y0 * 2 * g->scale) + toolbar_height; + } else { + /* scroll area into view with padding */ + int x0, y0, x1, y1; + int cx0, cy0, width, height; + int padding_available; + int correction; + + x0 = rect->x0 * 2 * g->scale; + y0 = rect->y0 * 2 * g->scale; + x1 = rect->x1 * 2 * g->scale; + y1 = rect->y1 * 2 * g->scale; + + cx0 = state.xscroll; + cy0 = -state.yscroll + toolbar_height; + width = state.visible.x1 - state.visible.x0; + height = state.visible.y1 - state.visible.y0 - toolbar_height; + + /* make sure we're visible */ + correction = (x1 - cx0 - width); + if (correction > 0) { + cx0 += correction; } - else if (sprite_bpp(overlay) != 8) { - LOG("overlay sprite is not 8bpp"); - overlay = NULL; + correction = (y1 - cy0 - height); + if (correction > 0) { + cy0 += correction; + } + if (x0 < cx0) { + cx0 = x0; + } + if (y0 < cy0) { + cy0 = y0; } - } - /* create the thumbnail sprite */ - bitmap = riscos_bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | - BITMAP_CLEAR_MEMORY); - if (!bitmap) { - LOG("Thumbnail initialisation failed."); - return; + /* try to give a SCROLL_VISIBLE_PADDING border of space around us */ + padding_available = (width - x1 + x0) / 2; + if (padding_available > 0) { + if (padding_available > SCROLL_VISIBLE_PADDING) { + padding_available = SCROLL_VISIBLE_PADDING; + } + correction = (cx0 + width - x1); + if (correction < padding_available) { + cx0 += padding_available; + } + correction = (x0 - cx0); + if (correction < padding_available) { + cx0 -= padding_available; + } + } + padding_available = (height - y1 + y0) / 2; + if (padding_available > 0) { + if (padding_available > SCROLL_VISIBLE_PADDING) { + padding_available = SCROLL_VISIBLE_PADDING; + } + correction = (cy0 + height - y1); + if (correction < padding_available) { + cy0 += padding_available; + } + correction = (y0 - cy0); + if (correction < padding_available) { + cy0 -= padding_available; + } + } + + state.xscroll = cx0; + state.yscroll = -cy0 + toolbar_height; } - riscos_bitmap_render(bitmap, h); - if (overlay) { - riscos_bitmap_overlay_sprite(bitmap, overlay); + ro_gui_window_open(PTR_WIMP_OPEN(&state)); + + return NSERROR_OK; +} + + +/** + * Find the current dimensions of a browser window's content area. + * + * \param gw gui window to measure + * \param width receives width of window + * \param height receives height of window + * \param scaled whether to return scaled values + */ +static nserror +gui_window_get_dimensions(struct gui_window *gw, + int *width, int *height, + bool scaled) +{ + /* use the cached window sizes */ + *width = gw->old_width / 2; + *height = gw->old_height / 2; + + if (scaled) { + *width /= gw->scale; + *height /= gw->scale; } - area = riscos_bitmap_convert_8bpp(bitmap); - riscos_bitmap_destroy(bitmap); - if (!area) { - LOG("Thumbnail conversion failed."); - return; + return NSERROR_OK; +} + + +/** + * Set the status bar of a browser window. + * + * \param g gui_window to update + * \param text new status text + */ +static void riscos_window_set_status(struct gui_window *g, const char *text) +{ + if (g->status_bar) { + ro_gui_status_bar_set_text(g->status_bar, text); } +} - /* choose a suitable sprite name */ - id = 0; - while (iconise_used[id]) - if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) { - id = iconise_next; - if ((unsigned)++iconise_next >= - NOF_ELEMENTS(iconise_used)) - iconise_next = 0; - break; - } - sprite_header = (osspriteop_header *)(area + 1); - len = sprintf(sprite_header->name, "ic_netsf%.2d", id); +/** + * Update the interface to reflect start of page loading. + * + * \param g window with start of load + */ +static void gui_window_start_throbber(struct gui_window *g) +{ + ro_gui_window_update_toolbar_buttons(g); + ro_gui_menu_refresh(ro_gui_browser_window_menu); + if (g->toolbar != NULL) + ro_toolbar_start_throbbing(g->toolbar); + g->active = true; +} - error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, - area, temp_fname); - if (error) { - LOG("xosspriteop_save_sprite_file: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("MiscError", error->errmess); - free(area); - return; - } - error = xwimpspriteop_merge_sprite_file(temp_fname); - if (error) { - LOG("xwimpspriteop_merge_sprite_file: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - remove(temp_fname); - free(area); + +/** + * Update the interface to reflect page loading stopped. + * + * \param g window with start of load + */ +static void gui_window_stop_throbber(struct gui_window *g) +{ + ro_gui_window_update_toolbar_buttons(g); + ro_gui_menu_refresh(ro_gui_browser_window_menu); + if (g->toolbar != NULL) + ro_toolbar_stop_throbbing(g->toolbar); + g->active = false; +} + +/** + * set favicon + */ +static void +gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon) +{ + if (g == NULL || g->toolbar == NULL) return; - } - memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ - strncpy(wi->title, g->title, sizeof(wi->title)); - wi->title[sizeof(wi->title) - 1] = '\0'; + ro_toolbar_set_site_favicon(g->toolbar, icon); +} - if (wimptextop_string_width(wi->title, 0) > 182) { - /* work around bug in Pinboard where it will fail to display - * the icon if the text is very wide */ - if (strlen(wi->title) > 10) - wi->title[10] = '\0'; /* pinboard does this anyway */ - while (wimptextop_string_width(wi->title, 0) > 182) - wi->title[strlen(wi->title) - 1] = '\0'; - } - wi->size = sizeof(wimp_full_message_window_info); - wi->your_ref = wi->my_ref; - error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, - wi->sender); + +/** + * Remove the caret, if present. + * + * \param g window with caret + */ +static void gui_window_remove_caret(struct gui_window *g) +{ + wimp_caret caret; + os_error *error; + + error = xwimp_get_caret_position(&caret); if (error) { - LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess); + LOG("xwimp_get_caret_position: 0x%x: %s", + error->errnum, error->errmess); ro_warn_user("WimpError", error->errmess); + return; } - else { - g->iconise_icon = id; - iconise_used[id] = true; + + if (caret.w == g->window) { + /* we have the caret: hide caret, but keep input focus */ + gui_window_place_caret(g, -100, -100, 0, NULL); } +} - free(area); + +/** + * Called when the gui_window has new content. + * + * \param g the gui_window that has new content + */ +static void gui_window_new_content(struct gui_window *g) +{ + ro_gui_menu_refresh(ro_gui_browser_window_menu); + ro_gui_window_update_toolbar_buttons(g); + ro_gui_dialog_close_persistent(g->window); + ro_toolbar_set_content_favicon(g->toolbar, g); } /** * Completes scrolling of a browser window * - * \param *drag The DragEnd event data block. - * \param *data gui window block pointer. + * \param drag The DragEnd event data block. + * \param data gui window block pointer. */ - static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data) { wimp_pointer pointer; @@ -3498,612 +3799,703 @@ static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data) /** - * Process Mouse_Click events in a toolbar's button bar. This does not handle - * other clicks in a toolbar: these are handled by the toolbar module itself. + * Starts drag scrolling of a browser window * - * \param *data The GUI window associated with the click. - * \param action_type The action type to be handled. - * \param action The action to process. + * \param g the window to scroll */ - -void ro_gui_window_toolbar_click(void *data, - toolbar_action_type action_type, union toolbar_action action) +static bool gui_window_scroll_start(struct gui_window *g) { - struct gui_window *g = data; - nserror err; - - if (g == NULL) - return; - - - if (action_type == TOOLBAR_ACTION_URL) { - switch (action.url) { - case TOOLBAR_URL_DRAG_URL: - { - gui_save_type save_type; - - if (!browser_window_has_content(g->bw)) - break; - - if (ro_gui_shift_pressed()) - save_type = GUI_SAVE_LINK_URL; - else - save_type = GUI_SAVE_LINK_TEXT; - - ro_gui_drag_save_link(save_type, - browser_window_get_url(g->bw), - browser_window_get_title(g->bw), g); - } - break; - - case TOOLBAR_URL_SELECT_HOTLIST: - ro_gui_window_action_add_bookmark(g); - break; - - case TOOLBAR_URL_ADJUST_HOTLIST: - ro_gui_window_action_remove_bookmark(g); - break; - - default: - break; - } + wimp_window_info_base info; + wimp_pointer pointer; + os_error *error; + wimp_drag drag; + int height; + int width; - return; + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; } + info.w = g->window; + error = xwimp_get_window_info_header_only((wimp_window_info*)&info); + if (error) { + LOG("xwimp_get_window_state: 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } - /* By now, the only valid action left is a button click. If it isn't - * one of those, give up. - */ - - if (action_type != TOOLBAR_ACTION_BUTTON) - return; - - switch (action.button) { - case TOOLBAR_BUTTON_BACK: - if (g->bw != NULL) - browser_window_history_back(g->bw, false); - break; - - case TOOLBAR_BUTTON_BACK_NEW: - if (g->bw != NULL) - browser_window_history_back(g->bw, true); - break; - - case TOOLBAR_BUTTON_FORWARD: - if (g->bw != NULL) - browser_window_history_forward(g->bw, false); - break; - - case TOOLBAR_BUTTON_FORWARD_NEW: - if (g->bw != NULL) - browser_window_history_forward(g->bw, true); - break; - - case TOOLBAR_BUTTON_STOP: - if (g->bw != NULL) - browser_window_stop(g->bw); - break; - - case TOOLBAR_BUTTON_RELOAD: - if (g->bw != NULL) - browser_window_reload(g->bw, false); - break; - - case TOOLBAR_BUTTON_RELOAD_ALL: - if (g->bw != NULL) - browser_window_reload(g->bw, true); - break; - - case TOOLBAR_BUTTON_HISTORY_LOCAL: - ro_gui_window_action_local_history(g); - break; - - case TOOLBAR_BUTTON_HISTORY_GLOBAL: - ro_gui_global_history_present(); - break; + width = info.extent.x1 - info.extent.x0; + height = info.extent.y1 - info.extent.y0; - case TOOLBAR_BUTTON_HOME: - ro_gui_window_action_home(g); - break; + drag.type = wimp_DRAG_USER_POINT; + drag.bbox.x1 = pointer.pos.x + info.xscroll; + drag.bbox.y0 = pointer.pos.y + info.yscroll; + drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0)); + drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0)); - case TOOLBAR_BUTTON_SEARCH: - ro_gui_window_action_search(g); - break; + if (g->toolbar) { + int tbar_height = ro_toolbar_full_height(g->toolbar); + drag.bbox.y0 -= tbar_height; + drag.bbox.y1 -= tbar_height; + } - case TOOLBAR_BUTTON_SCALE: - ro_gui_window_action_zoom(g); - break; + error = xwimp_drag_box(&drag); + if (error) { + LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } - case TOOLBAR_BUTTON_BOOKMARK_OPEN: - ro_gui_hotlist_present(); - break; + ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at, + NULL, g); + return true; +} - case TOOLBAR_BUTTON_BOOKMARK_ADD: - ro_gui_window_action_add_bookmark(g); - break; - case TOOLBAR_BUTTON_SAVE_SOURCE: - ro_gui_window_action_save(g, GUI_SAVE_SOURCE); - break; +/** + * Platform-dependent part of starting drag operation. + * + * \param g gui window containing the drag + * \param type type of drag the core is performing + * \param rect rectangle to constrain pointer to (relative to drag start coord) + * \return true iff succesful + */ +static bool +gui_window_drag_start(struct gui_window *g, + gui_drag_type type, + const struct rect *rect) +{ + wimp_pointer pointer; + wimp_drag drag; - case TOOLBAR_BUTTON_SAVE_COMPLETE: - ro_gui_window_action_save(g, GUI_SAVE_COMPLETE); - break; + if (rect != NULL) { + /* We have a box to constrain the pointer to, for the drag + * duration */ + os_error *error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } - case TOOLBAR_BUTTON_PRINT: - ro_gui_window_action_print(g); - break; + drag.type = wimp_DRAG_USER_POINT; + drag.bbox.x0 = pointer.pos.x + + (int)(rect->x0 * 2 * g->scale); + drag.bbox.y0 = pointer.pos.y + + (int)(rect->y0 * 2 * g->scale); + drag.bbox.x1 = pointer.pos.x + + (int)(rect->x1 * 2 * g->scale); + drag.bbox.y1 = pointer.pos.y + + (int)(rect->y1 * 2 * g->scale); - case TOOLBAR_BUTTON_UP: - err = browser_window_navigate_up(g->bw, false); - if (err != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(err), NULL); + error = xwimp_drag_box(&drag); + if (error) { + LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; } - break; + } - case TOOLBAR_BUTTON_UP_NEW: - err = browser_window_navigate_up(g->bw, true); - if (err != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(err), NULL); - } + switch (type) { + case GDRAGGING_SCROLLBAR: + /* Dragging a core scrollbar */ + ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at, + NULL, g); break; default: + /* Not handled here yet */ break; } - ro_gui_window_update_toolbar_buttons(g); + return true; } /** - * Handle Message_DataLoad (file dragged in) for a toolbar - * - * @todo This belongs in the toolbar module, and should be moved there - * once the module is able to usefully handle its own events. + * Save the specified content as a link. * - * \param g window - * \param message Message_DataLoad block - * \return true if the load was processed + * \param g The window containing the content + * \param url The url of the link + * \param title The title of the link */ - -bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message) +static nserror +gui_window_save_link(struct gui_window *g, nsurl *url, const char *title) { - if (message->data.data_xfer.file_type == osfile_TYPE_TEXT && - ro_gui_window_import_text(g, - message->data.data_xfer.file_name)) { - os_error *error; - - /* send DataLoadAck */ - message->action = message_DATA_LOAD_ACK; - message->your_ref = message->my_ref; - error = xwimp_send_message(wimp_USER_MESSAGE, message, - message->sender); - if (error) { - LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - } - return true; - } - return false; + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); + return NSERROR_OK; } -/* - * Helper code for the Wimp Event Handlers. - */ - /** - * Check if a particular menu handle is a browser window menu + * Display a menu of options for a form select control. * - * \param *menu The menu in question. - * \return true if this menu is a browser window menu + * \param g gui window containing form control + * \param control form control of type GADGET_SELECT */ - -bool ro_gui_window_check_menu(wimp_menu *menu) +static void +gui_window_create_form_select_menu(struct gui_window *g, + struct form_control *control) { - return (ro_gui_browser_window_menu == menu) ? true : false; -} - - -/** - * Return boolean flags to show what RISC OS types we can sensibly convert - * the given object into. - * - * \todo This should probably be somewhere else but in window.c, and - * should probably even be done in content_(). - * - * \param h The object to test. - * \param export_draw true on exit if a drawfile would be possible. - * \param export_sprite true on exit if a sprite would be possible. - * \return true if valid data is returned; else false. - */ + os_error *error; + wimp_pointer pointer; -bool ro_gui_window_content_export_types(struct hlcache_handle *h, - bool *export_draw, bool *export_sprite) -{ - bool found_type = false; + /* The first time the menu is opened, control bypasses the normal + * Menu Prepare event and so we prepare here. On any re-opens, + * ro_gui_window_prepare_form_select_menu() is called from the + * normal wimp event. + */ - if (export_draw != NULL) - *export_draw = false; - if (export_sprite != NULL) - *export_sprite = false; + if (!ro_gui_window_prepare_form_select_menu(g, control)) + return; - if (h != NULL && content_get_type(h) == CONTENT_IMAGE) { - switch (ro_content_native_type(h)) { - case osfile_TYPE_SPRITE: - /* bitmap types (Sprite export possible) */ - found_type = true; - if (export_sprite != NULL) - *export_sprite = true; - break; - case osfile_TYPE_DRAW: - /* vector types (Draw export possible) */ - found_type = true; - if (export_draw != NULL) - *export_draw = true; - break; - default: - break; - } + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + ro_gui_menu_destroy(); + return; } - return found_type; + gui_form_select_control = control; + ro_gui_menu_create(gui_form_select_menu, + pointer.pos.x, pointer.pos.y, g->window); } /** - * Prepare the page info window for use. + * Import text file into window * - * \param *g The GUI window block to use. + * \param g gui window containing textarea + * \param filename pathname of file to be imported + * \return true iff successful */ - -void ro_gui_window_prepare_pageinfo(struct gui_window *g) +static bool +ro_gui_window_import_text(struct gui_window *g, const char *filename) { - struct hlcache_handle *h = browser_window_get_content(g->bw); - char icon_buf[20] = "file_xxx"; - char enc_buf[40]; - const char *icon = icon_buf; - const char *title, *url; - lwc_string *mime; - const char *enc = "-"; - - assert(h); - - title = content_get_title(h); - if (title == NULL) - title = "-"; - url = nsurl_access(hlcache_handle_get_url(h)); - if (url == NULL) - url = "-"; - mime = content_get_mime_type(h); - - sprintf(icon_buf, "file_%x", ro_content_filetype(h)); - if (!ro_gui_wimp_sprite_exists(icon_buf)) - sprintf(icon_buf, "file_xxx"); + fileswitch_object_type obj_type; + os_error *error; + char *buf, *utf8_buf, *sp; + int size; + nserror ret; + const char *ep; + char *p; - if (content_get_type(h) == CONTENT_HTML) { - if (content_get_encoding(h, CONTENT_ENCODING_NORMAL)) { - snprintf(enc_buf, sizeof enc_buf, "%s (%s)", - content_get_encoding(h, CONTENT_ENCODING_NORMAL), - content_get_encoding(h, CONTENT_ENCODING_SOURCE)); - enc = enc_buf; - } else { - enc = messages_get("EncodingUnk"); - } + error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, + &size, NULL, NULL); + if (error) { + LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess); + ro_warn_user("FileError", error->errmess); + return true; /* was for us, but it didn't work! */ } - ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ICON, - icon, true); - ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TITLE, - title, true); - ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_URL, - url, true); - ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC, - enc, true); - ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE, - lwc_string_data(mime), true); - - lwc_string_unref(mime); -} - + /* Allocate one byte more than needed to ensure that the buffer is + * always terminated, regardless of file contents. + */ -/** - * Prepare the object info window for use - * - * \param *object the object for which information is to be displayed - * \param *target_url corresponding url, if any - */ + buf = calloc(size + 1, sizeof(char)); + if (!buf) { + ro_warn_user("NoMemory", NULL); + return true; + } -void ro_gui_window_prepare_objectinfo(struct hlcache_handle *object, nsurl *target_url) -{ - char icon_buf[20] = "file_xxx"; - const char *url; - lwc_string *mime; - const char *target = "-"; + error = xosfile_load_stamped(filename, (byte*)buf, + NULL, NULL, NULL, NULL, NULL); - sprintf(icon_buf, "file_%.3x",ro_content_filetype(object)); - if (!ro_gui_wimp_sprite_exists(icon_buf)) { - sprintf(icon_buf, "file_xxx"); + if (error) { + LOG("xosfile_load_stamped: 0x%x:%s", error->errnum, error->errmess); + ro_warn_user("LoadError", error->errmess); + free(buf); + return true; } - url = nsurl_access(hlcache_handle_get_url(object)); - if (url == NULL) { - url = "-"; + ret = utf8_from_local_encoding(buf, size, &utf8_buf); + if (ret != NSERROR_OK) { + /* bad encoding shouldn't happen */ + assert(ret != NSERROR_BAD_ENCODING); + LOG("utf8_from_local_encoding failed"); + free(buf); + ro_warn_user("NoMemory", NULL); + return true; } - mime = content_get_mime_type(object); + size = strlen(utf8_buf); - if (target_url != NULL) { - target = nsurl_access(target_url); - } + ep = utf8_buf + size; + p = utf8_buf; - ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_ICON, - icon_buf, true); - ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_URL, - url, true); - ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TARGET, - target, true); - ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TYPE, - lwc_string_data(mime), true); + /* skip leading whitespace */ + while (isspace(*p)) p++; - lwc_string_unref(mime); -} + sp = p; + while (*p && *p != '\r' && *p != '\n') + p += utf8_next(p, ep - p, 0); + *p = '\0'; + if (p > sp) + ro_gui_window_launch_url(g, sp); + + free(buf); + free(utf8_buf); + return true; +} -/* - * User Actions in the browser window - */ /** - * Launch a new url in the given window. - * - * \param g gui_window to update - * \param url1 url to be launched + * RISC OS browser window operation table */ +static struct gui_window_table window_table = { + .create = gui_window_create, + .destroy = gui_window_destroy, + .invalidate = ro_gui_window_invalidate_area, + .get_scroll = gui_window_get_scroll, + .set_scroll = gui_window_set_scroll, + .get_dimensions = gui_window_get_dimensions, + .update_extent = gui_window_update_extent, -void ro_gui_window_launch_url(struct gui_window *g, const char *url1) -{ - nserror error; - nsurl *url; - - if (url1 == NULL) - return; - - ro_gui_url_complete_close(); + .set_title = gui_window_set_title, + .set_url = ro_gui_window_set_url, + .set_icon = gui_window_set_icon, + .set_status = riscos_window_set_status, + .set_pointer = gui_window_set_pointer, + .place_caret = gui_window_place_caret, + .remove_caret = gui_window_remove_caret, + .save_link = gui_window_save_link, + .drag_start = gui_window_drag_start, + .scroll_start = gui_window_scroll_start, + .new_content = gui_window_new_content, + .start_throbber = gui_window_start_throbber, + .stop_throbber = gui_window_stop_throbber, + .create_form_select_menu = gui_window_create_form_select_menu, - error = nsurl_create(url1, &url); - if (error != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(error), 0); - } else { - ro_gui_window_set_url(g, url); + /* from save */ + .drag_save_object = gui_drag_save_object, + .drag_save_selection =gui_drag_save_selection, - browser_window_navigate(g->bw, url, - NULL, BW_NAVIGATE_HISTORY, - NULL, NULL, NULL); - nsurl_unref(url); - } -} + /* from textselection */ + .start_selection = gui_start_selection, +}; +struct gui_window_table *riscos_window_table = &window_table; -/** - * Perform a Navigate Home action on a browser window. - * - * \param *g The browser window to act on. - */ -void ro_gui_window_action_home(struct gui_window *g) +/* exported interface documented in riscos/window.h */ +void ro_gui_window_initialise(void) { - static const char *addr = NETSURF_HOMEPAGE; - nsurl *url; - nserror error; - - if (g == NULL || g->bw == NULL) - return; + /* Build the browser window menu. */ - if (nsoption_charp(homepage_url) != NULL) { - addr = nsoption_charp(homepage_url); - } + static const struct ns_menu browser_definition = { + "NetSurf", { + { "Page", BROWSER_PAGE, 0 }, + { "Page.PageInfo",BROWSER_PAGE_INFO, &dialog_pageinfo }, + { "Page.Save", BROWSER_SAVE, &dialog_saveas }, + { "Page.SaveComp", BROWSER_SAVE_COMPLETE, &dialog_saveas }, + { "Page.Export", NO_ACTION, 0 }, +#ifdef WITH_DRAW_EXPORT + { "Page.Export.Draw", BROWSER_EXPORT_DRAW, &dialog_saveas }, +#endif +#ifdef WITH_PDF_EXPORT + { "Page.Export.PDF", BROWSER_EXPORT_PDF, &dialog_saveas }, +#endif + { "Page.Export.Text", BROWSER_EXPORT_TEXT, &dialog_saveas }, + { "Page.SaveURL", NO_ACTION, 0 }, + { "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, &dialog_saveas }, + { "Page.SaveURL.URL", BROWSER_SAVE_URL_URL, &dialog_saveas }, + { "Page.SaveURL.LinkText", BROWSER_SAVE_URL_TEXT, &dialog_saveas }, + { "_Page.Print", BROWSER_PRINT, &dialog_print }, + { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 }, + { "Page.FindText", BROWSER_FIND_TEXT, &dialog_search }, + { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 }, + { "Object", BROWSER_OBJECT, 0 }, + { "Object.Object", BROWSER_OBJECT_OBJECT, 0 }, + { "Object.Object.ObjInfo", BROWSER_OBJECT_INFO, &dialog_objinfo }, + { "Object.Object.ObjSave", BROWSER_OBJECT_SAVE, &dialog_saveas }, + { "Object.Object.Export", BROWSER_OBJECT_EXPORT, 0 }, + { "Object.Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, &dialog_saveas }, +#ifdef WITH_DRAW_EXPORT + { "Object.Object.Export.ObjDraw", BROWSER_OBJECT_EXPORT_DRAW, &dialog_saveas }, +#endif + { "Object.Object.SaveURL", NO_ACTION, 0 }, + { "Object.Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, &dialog_saveas }, + { "Object.Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, &dialog_saveas }, + { "Object.Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, &dialog_saveas }, + { "Object.Object.ObjPrint", BROWSER_OBJECT_PRINT, 0 }, + { "Object.Object.ObjReload", BROWSER_OBJECT_RELOAD, 0 }, + { "Object.Link", BROWSER_OBJECT_LINK, 0 }, + { "Object.Link.LinkSave", BROWSER_LINK_SAVE, 0 }, + { "Object.Link.LinkSave.URI", BROWSER_LINK_SAVE_URI, &dialog_saveas }, + { "Object.Link.LinkSave.URL", BROWSER_LINK_SAVE_URL, &dialog_saveas }, + { "Object.Link.LinkSave.LinkText", BROWSER_LINK_SAVE_TEXT, &dialog_saveas }, + { "_Object.Link.LinkDload", BROWSER_LINK_DOWNLOAD, 0 }, + { "Object.Link.LinkNew", BROWSER_LINK_NEW_WINDOW, 0 }, + { "Selection", BROWSER_SELECTION, 0 }, + { "_Selection.SelSave", BROWSER_SELECTION_SAVE, &dialog_saveas }, + { "Selection.Copy", BROWSER_SELECTION_COPY, 0 }, + { "Selection.Cut", BROWSER_SELECTION_CUT, 0 }, + { "_Selection.Paste", BROWSER_SELECTION_PASTE, 0 }, + { "Selection.Clear", BROWSER_SELECTION_CLEAR, 0 }, + { "Selection.SelectAll", BROWSER_SELECTION_ALL, 0 }, + { "Navigate", NO_ACTION, 0 }, + { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 }, + { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 }, + { "Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 }, + { "_Navigate.UpLevel", BROWSER_NAVIGATE_UP, 0 }, + { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 }, + { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 }, + { "View", NO_ACTION, 0 }, + { "View.ScaleView", BROWSER_SCALE_VIEW, &dialog_zoom }, + { "View.Images", NO_ACTION, 0 }, + { "View.Images.ForeImg", BROWSER_IMAGES_FOREGROUND, 0 }, + { "View.Images.BackImg", BROWSER_IMAGES_BACKGROUND, 0 }, + { "View.Toolbars", NO_ACTION, 0 }, + { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, + { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 }, + { "_View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 }, + { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, + { "_View.Render", NO_ACTION, 0 }, + { "View.Render.RenderAnims", BROWSER_BUFFER_ANIMS, 0 }, + { "View.Render.RenderAll", BROWSER_BUFFER_ALL, 0 }, + { "_View.OptDefault", BROWSER_SAVE_VIEW, 0 }, + { "View.Window", NO_ACTION, 0 }, + { "View.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 }, + { "View.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 }, + { "_View.Window.WindowSize", BROWSER_WINDOW_COPY, 0 }, + { "View.Window.WindowReset", BROWSER_WINDOW_RESET, 0 }, + { "Utilities", NO_ACTION, 0 }, + { "Utilities.Hotlist", HOTLIST_SHOW, 0 }, + { "Utilities.Hotlist.HotlistAdd", HOTLIST_ADD_URL, 0 }, + { "Utilities.Hotlist.HotlistShow", HOTLIST_SHOW, 0 }, + { "Utilities.History", HISTORY_SHOW_GLOBAL, 0 }, + { "Utilities.History.HistLocal", HISTORY_SHOW_LOCAL, 0 }, + { "Utilities.History.HistGlobal", HISTORY_SHOW_GLOBAL, 0 }, + { "Utilities.Cookies", COOKIES_SHOW, 0 }, + { "Utilities.Cookies.ShowCookies", COOKIES_SHOW, 0 }, + { "Utilities.Cookies.DeleteCookies", COOKIES_DELETE, 0 }, + { "Help", HELP_OPEN_CONTENTS, 0 }, + { "Help.HelpContent", HELP_OPEN_CONTENTS, 0 }, + { "Help.HelpGuide", HELP_OPEN_GUIDE, 0 }, + { "_Help.HelpInfo", HELP_OPEN_INFORMATION, 0 }, + { "Help.HelpCredits", HELP_OPEN_CREDITS, 0 }, + { "_Help.HelpLicence", HELP_OPEN_LICENCE, 0 }, + { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 }, + {NULL, 0, 0} + } + }; + ro_gui_browser_window_menu = + ro_gui_menu_define_menu(&browser_definition); - error = nsurl_create(addr, &url); - if (error == NSERROR_OK) { - error = browser_window_navigate(g->bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); - } - if (error != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(error), 0); - } } -/** - * Open a new browser window. - * - * \param *g The browser window to act on. - */ - -void ro_gui_window_action_new_window(struct gui_window *g) +/* exported interface documented in riscos/window.h */ +nserror +ro_gui_window_invalidate_area(struct gui_window *g, const struct rect *rect) { - nserror error; + bool use_buffer; + int x0, y0, x1, y1; + struct update_box *cur; + wimp_window_info info; + os_error *error; - if (g == NULL || g->bw == NULL) - return; + assert(g); - error = browser_window_create(BW_CREATE_CLONE, - browser_window_get_url(g->bw), - NULL, g->bw, NULL); + if (rect == NULL) { + info.w = g->window; + error = xwimp_get_window_info_header_only(&info); + if (error) { + LOG("xwimp_get_window_info_header_only: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return NSERROR_INVALID; + } - if (error != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(error), 0); + error = xwimp_force_redraw(g->window, + info.extent.x0, info.extent.y0, + info.extent.x1, info.extent.y1); + if (error) { + LOG("xwimp_force_redraw: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return NSERROR_INVALID; + } + return NSERROR_OK; } -} + x0 = floorf(rect->x0 * 2 * g->scale); + y0 = -ceilf(rect->y1 * 2 * g->scale); + x1 = ceilf(rect->x1 * 2 * g->scale) + 1; + y1 = -floorf(rect->y0 * 2 * g->scale) + 1; + use_buffer = + (g->option.buffer_everything || g->option.buffer_animations); + + /* try to optimise buffered redraws */ + if (use_buffer) { + for (cur = pending_updates; cur != NULL; cur = cur->next) { + if ((cur->g != g) || (!cur->use_buffer)) { + continue; + } + if ((((cur->x0 - x1) < MARGIN) || + ((cur->x1 - x0) < MARGIN)) && + (((cur->y0 - y1) < MARGIN) || + ((cur->y1 - y0) < MARGIN))) { + cur->x0 = min(cur->x0, x0); + cur->y0 = min(cur->y0, y0); + cur->x1 = max(cur->x1, x1); + cur->y1 = max(cur->y1, y1); + return NSERROR_OK; + } + } + } + cur = malloc(sizeof(struct update_box)); + if (!cur) { + LOG("No memory for malloc."); + return NSERROR_NOMEM; + } + + cur->x0 = x0; + cur->y0 = y0; + cur->x1 = x1; + cur->y1 = y1; + cur->next = pending_updates; + pending_updates = cur; + cur->g = g; + cur->use_buffer = use_buffer; + + return NSERROR_OK; +} -/** - * Open a local history pane for a browser window. - * - * \param g The browser window to act on. - */ -void ro_gui_window_action_local_history(struct gui_window *gw) +/* exported function documented in riscos/window.h */ +nserror ro_gui_window_set_url(struct gui_window *g, nsurl *url) { - nserror res; + size_t idn_url_l; + char *idn_url_s = NULL; - if ((gw == NULL) || (gw->bw == NULL)) { - return; - } + if (g->toolbar) { + if (nsoption_bool(display_decoded_idn) == true) { + if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) + idn_url_s = NULL; + } - res = ro_gui_local_history_present(gw->window, gw->bw); + ro_toolbar_set_url(g->toolbar, idn_url_s ? idn_url_s : nsurl_access(url), true, false); - if (res != NSERROR_OK) { - ro_warn_user(messages_get_errorcode(res), 0); + if (idn_url_s) + free(idn_url_s); + + ro_gui_url_complete_start(g->toolbar); } -} + return NSERROR_OK; +} -/** - * Open a save dialogue for a browser window contents. - * - * \param *g The browser window to act on. - * \param save_type The type of save to open. - */ -void ro_gui_window_action_save(struct gui_window *g, gui_save_type save_type) +/* exported interface documented in riscos/window.h */ +void ro_gui_window_set_scale(struct gui_window *g, float scale) { - struct hlcache_handle *h; + g->scale = scale; + browser_window_set_scale(g->bw, scale, true); +} - if (g == NULL || g->bw == NULL || !browser_window_has_content(g->bw)) - return; - h = browser_window_get_content(g->bw); - if (h == NULL) - return; +/* exported interface documented in riscos/window.h */ +bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) +{ + os_error *error; + os_coord pos; - ro_gui_save_prepare(save_type, h, NULL, NULL, NULL); - ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); -} + /* Ignore directories etc. */ + if (0x1000 <= message->data.data_xfer.file_type) + return false; + if (!ro_gui_window_to_window_pos(g, message->data.data_xfer.pos.x, + message->data.data_xfer.pos.y, &pos)) + return false; -/** - * Open a text search dialogue for a browser window. - * - * \param *g The browser window to act on. - */ + if (browser_window_drop_file_at_point(g->bw, pos.x, pos.y, + message->data.data_xfer.file_name) == false) + return false; -void ro_gui_window_action_search(struct gui_window *g) -{ - if (g == NULL || g->bw == NULL || !browser_window_can_search(g->bw)) - return; + /* send DataLoadAck */ + message->action = message_DATA_LOAD_ACK; + message->your_ref = message->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender); + if (error) { + LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } - ro_gui_search_prepare(g->bw); - ro_gui_dialog_open_persistent(g->window, dialog_search, true); + return true; } -/** - * Open a zoom dialogue for a browser window. - * - * \param *g The browser window to act on. - */ - -void ro_gui_window_action_zoom(struct gui_window *g) +/* exported interface documented in riscos/window.h */ +void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data) { - if (g == NULL) - return; + os_coord pos; + struct gui_window *g = (struct gui_window *) data; - ro_gui_dialog_prepare_zoom(g); - ro_gui_dialog_open_persistent(g->window, dialog_zoom, true); + if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) + browser_window_mouse_track(g->bw, + ro_gui_mouse_drag_state(pointer->buttons, + wimp_BUTTON_DOUBLE_CLICK_DRAG), + pos.x, pos.y); } -/** - * Add a hotlist entry for a browser window. - * - * \param *g The browser window to act on. - */ - -static void ro_gui_window_action_add_bookmark(struct gui_window *g) +/* exported interface documented in riscos/window.h */ +void +ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi) { - nsurl *url; + /* sadly there is no 'legal' way to get the sprite into + * the Wimp sprite pool other than via a filing system */ + const char *temp_fname = "Pipe:$._tmpfile"; + struct browser_window *bw = g->bw; + osspriteop_header *overlay = NULL; + osspriteop_header *sprite_header; + struct bitmap *bitmap; + osspriteop_area *area; + int width = 34, height = 34; + struct hlcache_handle *h; + os_error *error; + int len, id; - if (g == NULL || g->bw == NULL || g->toolbar == NULL || - browser_window_has_content(g->bw) == false) - return; + assert(bw); - url = browser_window_get_url(g->bw); + h = browser_window_get_content(bw); + if (!h) return; - ro_gui_hotlist_add_page(url); - ro_toolbar_update_hotlist(g->toolbar); -} + /* if an overlay sprite is defined, locate it and gets its dimensions + * so that we can produce a thumbnail with the same dimensions */ + if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { + error = xosspriteop_read_sprite_info(osspriteop_PTR, + (osspriteop_area *)0x100, + (osspriteop_id)overlay, &width, &height, NULL, + NULL); + if (error) { + LOG("xosspriteop_read_sprite_info: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + overlay = NULL; + } else if (sprite_bpp(overlay) != 8) { + LOG("overlay sprite is not 8bpp"); + overlay = NULL; + } + } + /* create the thumbnail sprite */ + bitmap = riscos_bitmap_create(width, height, + BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); + if (!bitmap) { + LOG("Thumbnail initialisation failed."); + return; + } + riscos_bitmap_render(bitmap, h); + if (overlay) { + riscos_bitmap_overlay_sprite(bitmap, overlay); + } + area = riscos_bitmap_convert_8bpp(bitmap); + riscos_bitmap_destroy(bitmap); + if (!area) { + LOG("Thumbnail conversion failed."); + return; + } -/** - * Remove a hotlist entry for a browser window. - * - * \param *g The browser window to act on. - */ + /* choose a suitable sprite name */ + id = 0; + while (iconise_used[id]) + if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) { + id = iconise_next; + if ((unsigned)++iconise_next >= + NOF_ELEMENTS(iconise_used)) + iconise_next = 0; + break; + } -static void ro_gui_window_action_remove_bookmark(struct gui_window *g) -{ - nsurl *url; + sprite_header = (osspriteop_header *)(area + 1); + len = sprintf(sprite_header->name, "ic_netsf%.2d", id); - if (g == NULL || g->bw == NULL || g->toolbar == NULL || - browser_window_has_content(g->bw) == false) + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + area, temp_fname); + if (error) { + LOG("xosspriteop_save_sprite_file: 0x%x:%s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + free(area); return; + } - url = browser_window_get_url(g->bw); - - ro_gui_hotlist_remove_page(url); -} + error = xwimpspriteop_merge_sprite_file(temp_fname); + if (error) { + LOG("xwimpspriteop_merge_sprite_file: 0x%x:%s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + remove(temp_fname); + free(area); + return; + } + memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ + strncpy(wi->title, g->title, sizeof(wi->title)); + wi->title[sizeof(wi->title) - 1] = '\0'; -/** - * Open a print dialogue for a browser window. - * - * \param *g The browser window to act on. - */ + if (wimptextop_string_width(wi->title, 0) > 182) { + /* work around bug in Pinboard where it will fail to display + * the icon if the text is very wide */ + if (strlen(wi->title) > 10) + wi->title[10] = '\0'; /* pinboard does this anyway */ + while (wimptextop_string_width(wi->title, 0) > 182) + wi->title[strlen(wi->title) - 1] = '\0'; + } -void ro_gui_window_action_print(struct gui_window *g) -{ - if (g == NULL) - return; + wi->size = sizeof(wimp_full_message_window_info); + wi->your_ref = wi->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, + wi->sender); + if (error) { + LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + else { + g->iconise_icon = id; + iconise_used[id] = true; + } - ro_gui_print_prepare(g); - ro_gui_dialog_open_persistent(g->window, dialog_print, true); + free(area); } -/** - * Open a page info box for a browser window. - * - * \param *g The browser window to act on. - */ - -void ro_gui_window_action_page_info(struct gui_window *g) +/* exported interface documented in riscos/window.h */ +bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message) { - if (g == NULL || g->bw == NULL || - browser_window_has_content(g->bw) == false) - return; + if (message->data.data_xfer.file_type == osfile_TYPE_TEXT && + ro_gui_window_import_text(g, + message->data.data_xfer.file_name)) { + os_error *error; - ro_gui_window_prepare_pageinfo(g); - ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, false); + /* send DataLoadAck */ + message->action = message_DATA_LOAD_ACK; + message->your_ref = message->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, message, + message->sender); + if (error) { + LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + return true; + } + return false; } -/* - * Window and Toolbar Redraw and Update - */ +/* exported interface documented in riscos/window.h */ +bool ro_gui_window_check_menu(wimp_menu *menu) +{ + return (ro_gui_browser_window_menu == menu) ? true : false; +} -/** - * Redraws the content for all windows. - */ +/* exported interface documented in riscos/window.h */ void ro_gui_window_redraw_all(void) { struct gui_window *g; @@ -4113,25 +4505,7 @@ void ro_gui_window_redraw_all(void) } -/** - * Remove all pending update boxes for a window - * - * \param g gui_window - */ -void ro_gui_window_remove_update_boxes(struct gui_window *g) -{ - struct update_box *cur; - - for (cur = pending_updates; cur != NULL; cur = cur->next) { - if (cur->g == g) - cur->g = NULL; - } -} - - -/** - * Redraw any pending update boxes. - */ +/* exported interface documented in riscos/window.h */ void ro_gui_window_update_boxes(void) { osbool more; @@ -4214,10 +4588,7 @@ void ro_gui_window_update_boxes(void) } -/** - * Destroy all browser windows. - */ - +/* exported interface documented in riscos/window.h */ void ro_gui_window_quit(void) { while (window_list) { @@ -4229,13 +4600,10 @@ void ro_gui_window_quit(void) } -/** - * Animate the "throbbers" of all browser windows. - */ - +/* exported interface documented in riscos/window.h */ void ro_gui_throb(void) { - struct gui_window *g; + struct gui_window *g; for (g = window_list; g; g = g->next) { if (!g->active) @@ -4246,245 +4614,7 @@ void ro_gui_throb(void) } -/** - * Update the toolbar buttons for a given browser window to reflect the - * current state of its contents. - * - * Note that the parameters to this function are arranged so that it can be - * supplied to the toolbar module as an button state update callback. - * - * \param *g The browser window to update. - */ - -void ro_gui_window_update_toolbar_buttons(struct gui_window *g) -{ - struct browser_window *bw; - struct toolbar *toolbar; - - if (g == NULL || g->toolbar == NULL) - return; - - bw = g->bw; - toolbar = g->toolbar; - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_RELOAD, - !browser_window_reload_available(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_STOP, - !browser_window_stop_available(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_BACK, - !browser_window_back_available(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_FORWARD, - !browser_window_forward_available(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_UP, - !browser_window_up_available(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SEARCH, - !browser_window_can_search(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SCALE, - !browser_window_has_content(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_PRINT, - !browser_window_has_content(bw)); - - ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SAVE_SOURCE, - !browser_window_has_content(bw)); - - ro_toolbar_update_urlsuggest(toolbar); -} - - -/** - * Update a window to reflect a change in toolbar size: used as a callback by - * the toolbar module when a toolbar height changes. - * - * \param *data void pointer the window's gui_window struct - */ - -void ro_gui_window_update_toolbar(void *data) -{ - struct gui_window *g = (struct gui_window *) data; - - if (g != NULL) - gui_window_update_extent(g); -} - - -/** - * Save a new toolbar button configuration: used as a callback by the toolbar - * module when a buttonbar edit has finished. - * - * \param *data void pointer to the window's gui_window struct - * \param *config pointer to a malloc()'d button config string. - */ - -void ro_gui_window_save_toolbar_buttons(void *data, char *config) -{ - nsoption_set_charp(toolbar_browser, config); - ro_gui_save_options(); -} - - -/** - * Update a window and its toolbar to reflect a new theme: used as a callback - * by the toolbar module when a theme change affects a toolbar. - * - * \param *data void pointer to the window's gui_window struct - * \param ok true if the bar still exists; else false. - */ - -void ro_gui_window_update_theme(void *data, bool ok) -{ - struct gui_window *g = (struct gui_window *) data; - - if (g != NULL && g->toolbar != NULL) { - if (ok) { - gui_window_update_extent(g); - } else { - g->toolbar = NULL; - } - } -} - - -/* - * General Window Support - */ - -/** - * Import text file into window - * - * \param g gui window containing textarea - * \param filename pathname of file to be imported - * \return true iff successful - */ - -bool ro_gui_window_import_text(struct gui_window *g, const char *filename) -{ - fileswitch_object_type obj_type; - os_error *error; - char *buf, *utf8_buf, *sp; - int size; - nserror ret; - const char *ep; - char *p; - - error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, - &size, NULL, NULL); - if (error) { - LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("FileError", error->errmess); - return true; /* was for us, but it didn't work! */ - } - - /* Allocate one byte more than needed to ensure that the buffer is - * always terminated, regardless of file contents. - */ - - buf = calloc(size + 1, sizeof(char)); - if (!buf) { - ro_warn_user("NoMemory", NULL); - return true; - } - - error = xosfile_load_stamped(filename, (byte*)buf, - NULL, NULL, NULL, NULL, NULL); - - if (error) { - LOG("xosfile_load_stamped: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("LoadError", error->errmess); - free(buf); - return true; - } - - ret = utf8_from_local_encoding(buf, size, &utf8_buf); - if (ret != NSERROR_OK) { - /* bad encoding shouldn't happen */ - assert(ret != NSERROR_BAD_ENCODING); - LOG("utf8_from_local_encoding failed"); - free(buf); - ro_warn_user("NoMemory", NULL); - return true; - } - size = strlen(utf8_buf); - - ep = utf8_buf + size; - p = utf8_buf; - - /* skip leading whitespace */ - while (isspace(*p)) p++; - - sp = p; - while (*p && *p != '\r' && *p != '\n') - p += utf8_next(p, ep - p, 0); - *p = '\0'; - - if (p > sp) - ro_gui_window_launch_url(g, sp); - - free(buf); - free(utf8_buf); - return true; -} - - -/** - * Clones a browser window's options. - * - * \param new_gui the new gui window - * \param old_gui the gui window to clone from, or NULL for default - */ - -void ro_gui_window_clone_options( - struct gui_window *new_gui, - struct gui_window *old_gui) -{ - assert(new_gui); - - /* Clone the basic options - */ - if (!old_gui) { - new_gui->option.buffer_animations = nsoption_bool(buffer_animations); - new_gui->option.buffer_everything = nsoption_bool(buffer_everything); - } else { - new_gui->option = old_gui->option; - } - - /* Set up the toolbar - */ - if (new_gui->toolbar) { - ro_toolbar_set_display_buttons(new_gui->toolbar, - nsoption_bool(toolbar_show_buttons)); - ro_toolbar_set_display_url(new_gui->toolbar, - nsoption_bool(toolbar_show_address)); - ro_toolbar_set_display_throbber(new_gui->toolbar, - nsoption_bool(toolbar_show_throbber)); - if ((old_gui) && (old_gui->toolbar)) { - ro_toolbar_set_display_buttons(new_gui->toolbar, - ro_toolbar_get_display_buttons( - old_gui->toolbar)); - ro_toolbar_set_display_url(new_gui->toolbar, - ro_toolbar_get_display_url( - old_gui->toolbar)); - ro_toolbar_set_display_throbber(new_gui->toolbar, - ro_toolbar_get_display_throbber( - old_gui->toolbar)); - ro_toolbar_process(new_gui->toolbar, -1, true); - } - } -} - - -/** - * Makes a browser window's options the default. - * - * \param gui The riscos gui window to set default options in. - */ - +/* exported interface documented in riscos/window.h */ void ro_gui_window_default_options(struct gui_window *gui) { if (gui == NULL) @@ -4512,179 +4642,20 @@ void ro_gui_window_default_options(struct gui_window *gui) } -/* - * Custom Menu Support - */ - -/** - * Prepare or reprepare a form select menu, setting up the menu handle - * globals in the process. - * - * \param g The RISC OS gui window the menu is in. - * \param control The form control needing a menu. - * \return true if the menu is OK to be opened; else false. - */ - -bool ro_gui_window_prepare_form_select_menu(struct gui_window *g, - struct form_control *control) -{ - unsigned int item, entries; - char *text_convert, *temp; - struct form_option *option; - bool reopen = true; - nserror err; - - assert(control); - - /* enumerate the entries */ - entries = 0; - option = form_select_get_option(control, entries); - while (option != NULL) { - entries++; - option = form_select_get_option(control, entries); - } - - if (entries == 0) { - /* no menu to display */ - ro_gui_menu_destroy(); - return false; - } - - /* free riscos menu if there already is one */ - if ((gui_form_select_menu) && (control != gui_form_select_control)) { - for (item = 0; ; item++) { - free(gui_form_select_menu->entries[item].data. - indirected_text.text); - if (gui_form_select_menu->entries[item].menu_flags & - wimp_MENU_LAST) - break; - } - free(gui_form_select_menu->title_data.indirected_text.text); - free(gui_form_select_menu); - gui_form_select_menu = 0; - } - - /* allocate new riscos menu */ - if (!gui_form_select_menu) { - reopen = false; - gui_form_select_menu = malloc(wimp_SIZEOF_MENU(entries)); - if (!gui_form_select_menu) { - ro_warn_user("NoMemory", 0); - ro_gui_menu_destroy(); - return false; - } - err = utf8_to_local_encoding(messages_get("SelectMenu"), 0, - &text_convert); - if (err != NSERROR_OK) { - /* badenc should never happen */ - assert(err != NSERROR_BAD_ENCODING); - LOG("utf8_to_local_encoding failed"); - ro_warn_user("NoMemory", 0); - ro_gui_menu_destroy(); - return false; - } - gui_form_select_menu->title_data.indirected_text.text = - text_convert; - ro_gui_menu_init_structure(gui_form_select_menu, entries); - } - - /* initialise menu entries from form control */ - for (item = 0; item < entries; item++) { - option = form_select_get_option(control, item); - gui_form_select_menu->entries[item].menu_flags = 0; - if (option->selected) - gui_form_select_menu->entries[item].menu_flags = - wimp_MENU_TICKED; - if (!reopen) { - - /* convert spaces to hard spaces to stop things - * like 'Go Home' being treated as if 'Home' is a - * keyboard shortcut and right aligned in the menu. - */ - - temp = cnv_space2nbsp(option->text); - if (!temp) { - LOG("cnv_space2nbsp failed"); - ro_warn_user("NoMemory", 0); - ro_gui_menu_destroy(); - return false; - } - - err = utf8_to_local_encoding(temp, - 0, &text_convert); - if (err != NSERROR_OK) { - /* A bad encoding should never happen, - * so assert this */ - assert(err != NSERROR_BAD_ENCODING); - LOG("utf8_to_enc failed"); - ro_warn_user("NoMemory", 0); - ro_gui_menu_destroy(); - return false; - } - - free(temp); - - gui_form_select_menu->entries[item].data.indirected_text.text = - text_convert; - gui_form_select_menu->entries[item].data.indirected_text.size = - strlen(gui_form_select_menu->entries[item]. - data.indirected_text.text) + 1; - } - } - - gui_form_select_menu->entries[0].menu_flags |= - wimp_MENU_TITLE_INDIRECTED; - gui_form_select_menu->entries[item - 1].menu_flags |= wimp_MENU_LAST; - - return true; -} - -/** - * Process selections from a form select menu, passing them back to the core. - * - * \param *g The browser window affected by the menu. - * \param *selection The menu selection. - */ - -void ro_gui_window_process_form_select_menu(struct gui_window *g, - wimp_selection *selection) -{ - assert(g != NULL); - - if (selection->items[0] >= 0) - form_select_process_selection(gui_form_select_control, - selection->items[0]); -} - - -/* - * Window and Toolbar Lookup - */ - -/** - * Convert a RISC OS window handle to a gui_window. - * - * \param window RISC OS window handle. - * \return A pointer to a riscos gui window if found or NULL. - */ - +/* exported interface documented in riscos/window.h */ struct gui_window *ro_gui_window_lookup(wimp_w window) { struct gui_window *g; - for (g = window_list; g; g = g->next) - if (g->window == window) + for (g = window_list; g; g = g->next) { + if (g->window == window) { return g; + } + } return NULL; } -/** - * Convert a toolbar RISC OS window handle to a gui_window. - * - * \param window RISC OS window handle of a toolbar - * \return pointer to a structure if found, NULL otherwise - */ - +/* exported interface documented in riscos/window.h */ struct gui_window *ro_gui_toolbar_lookup(wimp_w window) { struct gui_window *g = NULL; @@ -4702,22 +4673,9 @@ struct gui_window *ro_gui_toolbar_lookup(wimp_w window) } -/* - * Core to RISC OS Conversions - */ - -/** - * Convert x,y screen co-ordinates into window co-ordinates. - * - * \param g gui window - * \param x x ordinate - * \param y y ordinate - * \param pos receives position in window co-ordinatates - * \return true iff conversion successful - */ - -bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, - os_coord *pos) +/* exported interface documented in riscos/window.h */ +bool +ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, os_coord *pos) { wimp_window_state state; os_error *error; @@ -4737,18 +4695,11 @@ bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, } -/** - * Convert x,y window co-ordinates into screen co-ordinates. - * - * \param g gui window - * \param x x ordinate - * \param y y ordinate - * \param pos receives position in screen co-ordinatates - * \return true iff conversion successful - */ - -bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, - os_coord *pos) +/* exported interface documented in riscos/window.h */ +bool ro_gui_window_to_screen_pos(struct gui_window *g, + int x, + int y, + os_coord *pos) { wimp_window_state state; os_error *error; @@ -4768,24 +4719,9 @@ bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, } -/* - * Miscellaneous Functions - * - * \TODO -- These items might well belong elsewhere. - */ - -/** - * Returns the state of the mouse buttons and modifiers keys for a - * mouse action, suitable for passing to the OS-independent - * browser window/ treeview/ etc code. - * - * \param buttons Wimp button state. - * \param type Wimp work-area/icon type for decoding. - * \return NetSurf core button state. - */ - -browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, - wimp_icon_flags type) +/* exported interface documented in riscos/window.h */ +enum browser_mouse_state +ro_gui_mouse_click_state(wimp_mouse_state buttons, wimp_icon_flags type) { browser_mouse_state state = 0; /* Blank state with nothing set */ static struct { @@ -4900,18 +4836,9 @@ browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, } -/** - * Returns the state of the mouse buttons and modifiers keys whilst - * dragging, for passing to the OS-independent browser window/ treeview/ - * etc code - * - * \param buttons Wimp button state. - * \param type Wimp work-area/icon type for decoding. - * \return NetSurf core button state. - */ - -browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons, - wimp_icon_flags type) +/* exported interface documented in riscos/window.h */ +browser_mouse_state +ro_gui_mouse_drag_state(wimp_mouse_state buttons, wimp_icon_flags type) { browser_mouse_state state = 0; /* Blank state with nothing set */ @@ -4939,10 +4866,7 @@ browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons, } -/** - * Returns true iff one or more Shift keys is held down - */ - +/* exported interface documented in riscos/window.h */ bool ro_gui_shift_pressed(void) { int shift = 0; @@ -4951,10 +4875,7 @@ bool ro_gui_shift_pressed(void) } -/** - * Returns true iff one or more Ctrl keys is held down - */ - +/* exported interface documented in riscos/window.h */ bool ro_gui_ctrl_pressed(void) { int ctrl = 0; @@ -4963,10 +4884,7 @@ bool ro_gui_ctrl_pressed(void) } -/** - * Returns true iff one or more Alt keys is held down - */ - +/* exported interface documented in riscos/window.h */ bool ro_gui_alt_pressed(void) { int alt = 0; @@ -4974,36 +4892,41 @@ bool ro_gui_alt_pressed(void) return (alt == 0xff); } -static struct gui_window_table window_table = { - .create = gui_window_create, - .destroy = gui_window_destroy, - .invalidate = ro_gui_window_invalidate_area, - .get_scroll = gui_window_get_scroll, - .set_scroll = gui_window_set_scroll, - .get_dimensions = gui_window_get_dimensions, - .update_extent = gui_window_update_extent, - .set_title = gui_window_set_title, - .set_url = ro_gui_window_set_url, - .set_icon = gui_window_set_icon, - .set_status = riscos_window_set_status, - .set_pointer = gui_window_set_pointer, - .place_caret = gui_window_place_caret, - .remove_caret = gui_window_remove_caret, - .save_link = gui_window_save_link, - .drag_start = gui_window_drag_start, - .scroll_start = gui_window_scroll_start, - .new_content = gui_window_new_content, - .start_throbber = gui_window_start_throbber, - .stop_throbber = gui_window_stop_throbber, - .create_form_select_menu = gui_window_create_form_select_menu, +/* exported interface documented in riscos/window.h */ +void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) +{ + static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT; + struct ro_gui_pointer_entry *entry; + os_error *error; - /* from save */ - .drag_save_object = gui_drag_save_object, - .drag_save_selection =gui_drag_save_selection, + if (shape == curr_pointer) + return; - /* from textselection */ - .start_selection = gui_start_selection, -}; + assert(shape < sizeof ro_gui_pointer_table / + sizeof ro_gui_pointer_table[0]); -struct gui_window_table *riscos_window_table = &window_table; + entry = &ro_gui_pointer_table[shape]; + + if (entry->wimp_area) { + /* pointer in the Wimp's sprite area */ + error = xwimpspriteop_set_pointer_shape(entry->sprite_name, + 1, entry->xactive, entry->yactive, 0, 0); + if (error) { + LOG("xwimpspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + } else { + /* pointer in our own sprite area */ + error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA, + gui_sprites, + (osspriteop_id) entry->sprite_name, + 1, entry->xactive, entry->yactive, 0, 0); + if (error) { + LOG("xosspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + } + + curr_pointer = shape; +} diff --git a/frontends/riscos/window.h b/frontends/riscos/window.h index 30b096580..0a5bd43c2 100644 --- a/frontends/riscos/window.h +++ b/frontends/riscos/window.h @@ -30,10 +30,21 @@ struct nsurl; extern struct gui_window_table *riscos_window_table; +/** + * Initialise the browser window module and its menus. + */ void ro_gui_window_initialise(void); + +/** + * Check if a particular menu handle is a browser window menu + * + * \param menu The menu in question. + * \return true if this menu is a browser window menu + */ bool ro_gui_window_check_menu(wimp_menu *menu); + /** * Set the contents of a window's address bar. * @@ -42,6 +53,7 @@ bool ro_gui_window_check_menu(wimp_menu *menu); */ nserror ro_gui_window_set_url(struct gui_window *g, struct nsurl *url); + /** * Cause an area of a window to be invalidated * @@ -56,5 +68,186 @@ nserror ro_gui_window_set_url(struct gui_window *g, struct nsurl *url); */ nserror ro_gui_window_invalidate_area(struct gui_window *g, const struct rect *rect); + +/** + * Set a gui_window's scale + */ +void ro_gui_window_set_scale(struct gui_window *g, float scale); + + +/** + * Handle Message_DataLoad (file dragged in) for a window. + * + * If the file was dragged into a form file input, it is used as the value. + * + * \param g window + * \param message Message_DataLoad block + * \return true if the load was processed + */ +bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message); + + +/** + * Handle pointer movements in a browser window. + * + * \param pointer new mouse position + * \param data browser window that the pointer is in + */ +void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data); + + +/** + * Window is being iconised. + * + * Create a suitable thumbnail sprite (which, sadly, must be in the + * Wimp sprite pool), and return the sprite name and truncated title + * to the iconiser + * + * \param g the gui window being iconised + * \param wi the WindowInfo message from the iconiser + */ +void ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi); + + +/** + * Handle Message_DataLoad (file dragged in) for a toolbar + * + * @todo This belongs in the toolbar module, and should be moved there + * once the module is able to usefully handle its own events. + * + * \param g window + * \param message Message_DataLoad block + * \return true if the load was processed + */ +bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message); + + +/** + * Redraws the content for all windows. + */ +void ro_gui_window_redraw_all(void); + + +/** + * Redraw any pending update boxes. + */ +void ro_gui_window_update_boxes(void); + + +/** + * Destroy all browser windows. + */ +void ro_gui_window_quit(void); + + +/** + * Close all browser windows + * + * no need for a separate fn same operation as quit +*/ +#define ro_gui_window_close_all ro_gui_window_quit + + +/** + * Animate the "throbbers" of all browser windows. + */ +void ro_gui_throb(void); + +/** + * Makes a browser window's options the default. + * + * \param gui The riscos gui window to set default options in. + */ +void ro_gui_window_default_options(struct gui_window *gui); + + +/** + * Convert a RISC OS window handle to a gui_window. + * + * \param window RISC OS window handle. + * \return A pointer to a riscos gui window if found or NULL. + */ +struct gui_window *ro_gui_window_lookup(wimp_w window); + + +/** + * Convert a toolbar RISC OS window handle to a gui_window. + * + * \param window RISC OS window handle of a toolbar + * \return pointer to a structure if found, NULL otherwise + */ +struct gui_window *ro_gui_toolbar_lookup(wimp_w window); + + +/** + * Convert x,y screen co-ordinates into window co-ordinates. + * + * \param g gui window + * \param x x ordinate + * \param y y ordinate + * \param pos receives position in window co-ordinatates + * \return true iff conversion successful + */ +bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, os_coord *pos); + + +/** + * Convert x,y window co-ordinates into screen co-ordinates. + * + * \param g gui window + * \param x x ordinate + * \param y y ordinate + * \param pos receives position in screen co-ordinatates + * \return true iff conversion successful + */ +bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, os_coord *pos); + +/** + * Returns the state of the mouse buttons and modifiers keys for a + * mouse action, suitable for passing to the OS-independent + * browser window/ treeview/ etc code. + * + * \param buttons Wimp button state. + * \param type Wimp work-area/icon type for decoding. + * \return NetSurf core button state. + */ +enum browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, wimp_icon_flags type); + + +/** + * Returns the state of the mouse buttons and modifiers keys whilst + * dragging, for passing to the OS-independent browser window/ treeview/ + * etc code + * + * \param buttons Wimp button state. + * \param type Wimp work-area/icon type for decoding. + * \return NetSurf core button state. + */ +enum browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons, wimp_icon_flags type); + + +/** + * Returns true iff one or more Shift keys is held down + */ +bool ro_gui_shift_pressed(void); + + +/** + * Returns true iff one or more Ctrl keys is held down + */ +bool ro_gui_ctrl_pressed(void); + + +/** + * Returns true iff one or more Alt keys is held down + */ +bool ro_gui_alt_pressed(void); + + +/** + * Change mouse pointer shape + */ +void gui_window_set_pointer(struct gui_window *g, enum gui_pointer_shape shape); + #endif diff --git a/frontends/windows/cookies.c b/frontends/windows/cookies.c index c4880fa1c..b3c56da8c 100644 --- a/frontends/windows/cookies.c +++ b/frontends/windows/cookies.c @@ -136,7 +136,7 @@ static nserror nsw32_cookie_init(HINSTANCE hInstance) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsw32_cookie_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/windows/corewindow.c b/frontends/windows/corewindow.c index adf1c6552..3c31c5e46 100644 --- a/frontends/windows/corewindow.c +++ b/frontends/windows/corewindow.c @@ -211,7 +211,7 @@ nsw32_corewindow_vscroll(struct nsw32_corewindow *nsw32_cw, NULL, NULL, NULL, - SW_ERASE | SW_INVALIDATE); + SW_INVALIDATE); /** * /todo win32 corewindow vertical scrolling needs us to @@ -278,7 +278,7 @@ nsw32_corewindow_hscroll(struct nsw32_corewindow *nsw32_cw, NULL, NULL, NULL, - SW_ERASE | SW_INVALIDATE); + SW_INVALIDATE); return 0; } @@ -286,18 +286,40 @@ nsw32_corewindow_hscroll(struct nsw32_corewindow *nsw32_cw, static LRESULT nsw32_corewindow_mousedown(struct nsw32_corewindow *nsw32_cw, + HWND hwnd, int x, int y, browser_mouse_state button) { + SCROLLINFO si; /* scroll information */ + + /* get scroll positions */ + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + GetScrollInfo(hwnd, SB_HORZ, &si); + x += si.nPos; + GetScrollInfo(hwnd, SB_VERT, &si); + y += si.nPos; + nsw32_cw->mouse(nsw32_cw, button, x, y); return 0; } static LRESULT nsw32_corewindow_mouseup(struct nsw32_corewindow *nsw32_cw, + HWND hwnd, int x, int y, browser_mouse_state button) { + SCROLLINFO si; /* scroll information */ + + /* get scroll positions */ + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + GetScrollInfo(hwnd, SB_HORZ, &si); + x += si.nPos; + GetScrollInfo(hwnd, SB_VERT, &si); + y += si.nPos; + nsw32_cw->mouse(nsw32_cw, button, x, y); return 0; } @@ -342,25 +364,25 @@ nsw32_window_corewindow_event_callback(HWND hwnd, return nsw32_corewindow_hscroll(nsw32_cw, hwnd, wparam); case WM_LBUTTONDOWN: - return nsw32_corewindow_mousedown(nsw32_cw, + return nsw32_corewindow_mousedown(nsw32_cw, hwnd, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), BROWSER_MOUSE_PRESS_1); case WM_RBUTTONDOWN: - return nsw32_corewindow_mousedown(nsw32_cw, + return nsw32_corewindow_mousedown(nsw32_cw, hwnd, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), BROWSER_MOUSE_PRESS_2); case WM_LBUTTONUP: - return nsw32_corewindow_mouseup(nsw32_cw, + return nsw32_corewindow_mouseup(nsw32_cw, hwnd, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), BROWSER_MOUSE_CLICK_1); case WM_RBUTTONUP: - return nsw32_corewindow_mouseup(nsw32_cw, + return nsw32_corewindow_mouseup(nsw32_cw, hwnd, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), BROWSER_MOUSE_CLICK_2); @@ -393,14 +415,22 @@ nsw32_cw_invalidate_area(struct core_window *cw, const struct rect *rect) RECT redrawrect; if (rect != NULL) { - redrawrectp = &redrawrect; + SCROLLINFO si; /* scroll information */ + + /* get scroll positions */ + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + GetScrollInfo(nsw32_cw->hWnd, SB_HORZ, &si); + redrawrect.left = (long)rect->x0 - si.nPos; + redrawrect.right = (long)rect->x1 - si.nPos; - redrawrect.left = (long)rect->x0; - redrawrect.top = (long)rect->y0; - redrawrect.right =(long)rect->x1; - redrawrect.bottom = (long)rect->y1; + GetScrollInfo(nsw32_cw->hWnd, SB_VERT, &si); + redrawrect.top = (long)rect->y0 - si.nPos; + redrawrect.bottom = (long)rect->y1 - si.nPos; + redrawrectp = &redrawrect; } + RedrawWindow(nsw32_cw->hWnd, redrawrectp, NULL, @@ -456,7 +486,7 @@ static void nsw32_cw_drag_status(struct core_window *cw, core_window_drag_status ds) { struct nsw32_corewindow *nsw32_cw = (struct nsw32_corewindow *)cw; - nsw32_cw->drag_staus = ds; + nsw32_cw->drag_status = ds; } @@ -478,6 +508,7 @@ nsw32_corewindow_init(HINSTANCE hInstance, /* setup the core window callback table */ nsw32_cw->cb_table = &nsw32_cw_cb_table; + nsw32_cw->drag_status = CORE_WINDOW_DRAG_NONE; /* start with the content area being as small as possible */ nsw32_cw->content_width = -1; diff --git a/frontends/windows/corewindow.h b/frontends/windows/corewindow.h index b78c72e8c..cffae3cbd 100644 --- a/frontends/windows/corewindow.h +++ b/frontends/windows/corewindow.h @@ -38,7 +38,7 @@ struct nsw32_corewindow { const char *title; /** drag status set by core */ - core_window_drag_status drag_staus; + core_window_drag_status drag_status; /** table of callbacks for core window operations */ struct core_window_callback_table *cb_table; diff --git a/frontends/windows/global_history.c b/frontends/windows/global_history.c index 0ba013bf0..dcc75ba21 100644 --- a/frontends/windows/global_history.c +++ b/frontends/windows/global_history.c @@ -126,7 +126,7 @@ static nserror nsw32_global_history_init(HINSTANCE hInstance) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsw32_global_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/windows/hotlist.c b/frontends/windows/hotlist.c index 0efe76f79..e8dd90b34 100644 --- a/frontends/windows/hotlist.c +++ b/frontends/windows/hotlist.c @@ -130,7 +130,7 @@ static nserror nsw32_hotlist_init(HINSTANCE hInstance) return NSERROR_OK; } - ncwin = malloc(sizeof(struct nsw32_hotlist_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/frontends/windows/local_history.c b/frontends/windows/local_history.c index f4474236e..722d365e7 100644 --- a/frontends/windows/local_history.c +++ b/frontends/windows/local_history.c @@ -111,11 +111,7 @@ nsw32_local_history_draw(struct nsw32_corewindow *nsw32_cw, lhw = (struct nsw32_local_history_window *)nsw32_cw; - local_history_redraw(lhw->session, - r->x0 - scrollx, - r->y0 - scrolly, - r, - &ctx); + local_history_redraw(lhw->session, -scrollx, -scrolly, r, &ctx); return NSERROR_OK; } @@ -147,7 +143,7 @@ nsw32_local_history_init(HINSTANCE hInstance, return res; } - ncwin = malloc(sizeof(struct nsw32_local_history_window)); + ncwin = calloc(1, sizeof(*ncwin)); if (ncwin == NULL) { return NSERROR_NOMEM; } diff --git a/render/html.c b/render/html.c index 62b7f3eec..a573ef5f5 100644 --- a/render/html.c +++ b/render/html.c @@ -706,7 +706,6 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw) { dom_event_target *node; dom_node_type type; - dom_string *name; dom_exception exc; html_content *htmlc = pw; @@ -722,16 +721,19 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw) exc = dom_node_get_node_type(node, &type); if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) { /* an element node has been modified */ - exc = dom_node_get_node_name(node, &name); - if ((exc == DOM_NO_ERR) && (name != NULL)) { + dom_html_element_type tag_type; - if (dom_string_caseless_isequal(name, - corestring_dom_style)) { - html_css_update_style(htmlc, - (dom_node *)node); - } + exc = dom_html_element_get_tag_type(node, &tag_type); + if (exc != DOM_NO_ERR) { + tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN; + } - dom_string_unref(name); + switch (tag_type) { + case DOM_HTML_ELEMENT_TYPE_STYLE: + html_css_update_style(htmlc, (dom_node *)node); + break; + default: + break; } } dom_node_unref(node); |