diff options
Diffstat (limited to 'desktop')
45 files changed, 3517 insertions, 1664 deletions
diff --git a/desktop/Makefile b/desktop/Makefile index f7020074e..218f60e67 100644 --- a/desktop/Makefile +++ b/desktop/Makefile @@ -8,12 +8,12 @@ S_DESKTOP := cookie_manager.c knockout.c hotlist.c mouse.c \ S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP)) # version.c needs the testament -desktop/version.c: testament utils/testament.h +desktop/version.c: testament $(OBJROOT)/testament.h # S_BROWSER are sources related to full browsers but are common # between RISC OS, GTK, BeOS and AmigaOS builds -S_BROWSER := browser.c download.c frames.c local_history.c netsurf.c \ - save_complete.c save_text.c selection.c textinput.c +S_BROWSER := browser.c browser_history.c download.c frames.c netsurf.c \ + save_complete.c save_text.c selection.c textinput.c gui_factory.c S_BROWSER := $(addprefix desktop/,$(S_BROWSER)) diff --git a/desktop/browser.c b/desktop/browser.c index d159a5599..1fa9de648 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -41,15 +41,14 @@ #include "content/fetch.h" #include "content/hlcache.h" #include "content/urldb.h" -#include "desktop/401login.h" +#include "desktop/browser_history.h" #include "desktop/browser_private.h" #include "desktop/download.h" #include "desktop/frames.h" #include "desktop/global_history.h" -#include "desktop/gui.h" +#include "desktop/gui_factory.h" #include "desktop/hotlist.h" #include "desktop/knockout.h" -#include "desktop/local_history.h" #include "utils/nsoption.h" #include "desktop/scrollbar.h" #include "desktop/selection.h" @@ -60,22 +59,18 @@ #include "render/form.h" #include "render/html.h" #include "render/box.h" +#include "utils/corestrings.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/nsurl.h" -#include "utils/schedule.h" -#include "utils/url.h" #include "utils/utils.h" #include "utils/utf8.h" -/** one or more windows require a reformat */ -bool browser_reformat_pending; /** maximum frame depth */ #define FRAME_DEPTH 8 - /** * Get position of scrollbar widget within browser window. * @@ -295,12 +290,12 @@ bool browser_window_redraw_ready(struct browser_window *bw) return true; } -/* exported interface, documented in browser.h */ +/* exported interface, documented in browser_private.h */ void browser_window_update_extent(struct browser_window *bw) { if (bw->window != NULL) /* Front end window */ - gui_window_update_extent(bw->window); + guit->window->update_extent(bw->window); else /* Core-managed browser window */ browser_window_handle_scrollbars(bw); @@ -391,7 +386,7 @@ void browser_window_set_drag_type(struct browser_window *bw, break; } - gui_window_drag_start(top_bw->window, gtype, rect); + guit->window->drag_start(top_bw->window, gtype, rect); } } @@ -484,7 +479,7 @@ void browser_window_scroll_visible(struct browser_window *bw, if (bw->window != NULL) { /* Front end window */ - gui_window_scroll_visible(bw->window, + guit->window->scroll_visible(bw->window, rect->x0, rect->y0, rect->x1, rect->y1); } else { /* Core managed browser window */ @@ -499,7 +494,7 @@ void browser_window_scroll_visible(struct browser_window *bw, void browser_window_set_scroll(struct browser_window *bw, int x, int y) { if (bw->window != NULL) { - gui_window_set_scroll(bw->window, x, y); + guit->window->set_scroll(bw->window, x, y); } else { if (bw->scroll_x != NULL) scrollbar_set(bw->scroll_x, x, false); @@ -661,11 +656,21 @@ bool browser_window_drop_file_at_point(struct browser_window *bw, return false; } +void browser_window_set_gadget_filename(struct browser_window *bw, + struct form_control *gadget, const char *fn) +{ + html_set_file_gadget_filename(bw->current_content, + gadget, fn); +} + /* exported interface, documented in browser.h */ -void browser_window_debug_dump(struct browser_window *bw, FILE *f) +nserror browser_window_debug_dump(struct browser_window *bw, FILE *f, enum content_debug op) { - if (bw->current_content != NULL) - content_debug_dump(bw->current_content, f); + if (bw->current_content == NULL) { + return NSERROR_OK; + } + + return content_debug_dump(bw->current_content, f, op); } /** slow script handler @@ -683,64 +688,81 @@ static bool slow_script(void *ctx) } /* exported interface, documented in desktop/browser.h */ - -nserror -browser_window_create(enum browser_window_nav_flags flags, - nsurl *url, - nsurl *referrer, - struct browser_window *clone, - struct browser_window **ret_bw) +nserror browser_window_create(enum browser_window_create_flags flags, + nsurl *url, nsurl *referrer, + struct browser_window *existing, + struct browser_window **bw) { - struct browser_window *bw; - struct browser_window *top; + gui_window_create_flags gw_flags = GW_CREATE_NONE; + struct browser_window *ret; - /* caller must provide window to clone or be adding to history */ - assert(clone || - ((flags & BROWSER_WINDOW_HISTORY) != 0)); + /* Check parameters */ + if (flags & BW_CREATE_CLONE) { + if (existing == NULL) { + assert(0 && "Failed: No existing window provided."); + return NSERROR_BAD_PARAMETER; + } + } + if (!(flags & BW_CREATE_HISTORY)) { + if (!(flags & BW_CREATE_CLONE) || existing == NULL) { + assert(0 && "Failed: Must have existing for history."); + return NSERROR_BAD_PARAMETER; + } + } - if ((bw = calloc(1, sizeof(struct browser_window))) == NULL) { + if ((ret = calloc(1, sizeof(struct browser_window))) == NULL) { warn_user("NoMemory", 0); return NSERROR_NOMEM; } /* new javascript context for window */ - bw->jsctx = js_newcontext(nsoption_int(script_timeout), + ret->jsctx = js_newcontext(nsoption_int(script_timeout), slow_script, NULL); /* Initialise common parts */ - browser_window_initialise_common(bw, clone); + browser_window_initialise_common(flags, ret, existing); /* window characteristics */ - bw->browser_window_type = BROWSER_WINDOW_NORMAL; - bw->scrolling = SCROLLING_YES; - bw->border = true; - bw->no_resize = true; - bw->last_action = wallclock(); - bw->focus = bw; - - /* gui window */ - /* from the front end's pov, it clones the top level browser window, - * so find that. */ - top = browser_window_get_root(clone); - - bw->window = gui_create_browser_window(bw, - top, - ((flags & BROWSER_WINDOW_TAB) != 0)); - - if (bw->window == NULL) { - browser_window_destroy(bw); + ret->browser_window_type = BROWSER_WINDOW_NORMAL; + ret->scrolling = SCROLLING_YES; + ret->border = true; + ret->no_resize = true; + ret->last_action = wallclock(); + ret->focus = ret; + + /* The existing gui_window is on the top-level existing + * browser_window. */ + existing = browser_window_get_root(existing); + + /* Set up gui_window creation flags */ + if (flags & BW_CREATE_TAB) + gw_flags |= GW_CREATE_TAB; + if (flags & BW_CREATE_CLONE) + gw_flags |= GW_CREATE_CLONE; + + ret->window = guit->window->create(ret, + (existing != NULL) ? existing->window : NULL, + gw_flags); + + if (ret->window == NULL) { + browser_window_destroy(ret); return NSERROR_BAD_PARAMETER; } if (url != NULL) { - flags |= BROWSER_WINDOW_VERIFIABLE; - browser_window_navigate(bw, url, referrer, flags, NULL, NULL, NULL); + enum browser_window_nav_flags nav_flags = BW_NAVIGATE_NONE; + if (flags & BW_CREATE_UNVERIFIABLE) + nav_flags |= BW_NAVIGATE_UNVERIFIABLE; + if (flags & BW_CREATE_HISTORY) + nav_flags |= BW_NAVIGATE_HISTORY; + browser_window_navigate(ret, url, referrer, nav_flags, NULL, + NULL, NULL); } - if (ret_bw != NULL) { - *ret_bw = bw; + if (bw != NULL) { + *bw = ret; } return NSERROR_OK; @@ -750,25 +772,39 @@ browser_window_create(enum browser_window_nav_flags flags, /** * Initialise common parts of a browser window * - * \param bw The window to initialise - * \param clone The window to clone, or NULL if none + * \param flags Flags to control operation + * \param bw The window to initialise + * \param existing The existing window if cloning, else NULL */ -void browser_window_initialise_common(struct browser_window *bw, - struct browser_window *clone) +nserror browser_window_initialise_common(enum browser_window_create_flags flags, + struct browser_window *bw, struct browser_window *existing) { + nserror err; assert(bw); - if (!clone) - bw->history = history_create(); - else - bw->history = history_clone(clone->history); + if (flags & BW_CREATE_CLONE) { + assert(existing != NULL); + + /* clone history */ + err = browser_window_history_clone(existing, bw); + + /* copy the scale */ + bw->scale = existing->scale; + } else { + /* create history */ + err = browser_window_history_create(bw); + + /* default scale */ + bw->scale = (float) nsoption_int(scale) / 100.0; + } + + if (err != NSERROR_OK) + return err; /* window characteristics */ bw->refresh_interval = -1; - bw->reformat_pending = false; bw->drag_type = DRAGGING_NONE; - bw->scale = (float) nsoption_int(scale) / 100.0; bw->scroll_x = NULL; bw->scroll_y = NULL; @@ -780,6 +816,8 @@ void browser_window_initialise_common(struct browser_window *bw, bw->status_text_len = 0; bw->status_match = 0; bw->status_miss = 0; + + return NSERROR_OK; } /** @@ -808,7 +846,7 @@ browser_window_download(struct browser_window *bw, NULL, NULL, &l); if (error == NSERROR_NO_FETCH_HANDLER) { /* no internal handler for this type, call out to frontend */ - gui_launch_url(nsurl_access(url)); + error = guit->browser->launch_url(url); } else if (error != NSERROR_OK) { LOG(("Failed to fetch download: %d", error)); } else { @@ -861,7 +899,7 @@ static void browser_window_start_throbber(struct browser_window *bw) while (bw->parent) bw = bw->parent; - gui_window_start_throbber(bw->window); + guit->window->start_throbber(bw->window); } @@ -878,8 +916,9 @@ static void browser_window_stop_throbber(struct browser_window *bw) while (bw->parent) bw = bw->parent; - if (!browser_window_check_throbber(bw)) - gui_window_stop_throbber(bw->window); + if (!browser_window_check_throbber(bw)) { + guit->window->stop_throbber(bw->window); + } } @@ -912,7 +951,7 @@ static nserror browser_window_favicon_callback(hlcache_handle *c, /* content_get_bitmap on the hlcache_handle should give * us the favicon bitmap at this point */ - gui_window_set_icon(bw->window, c); + guit->window->set_icon(bw->window, c); break; case CONTENT_MSG_ERROR: @@ -960,7 +999,6 @@ static nserror browser_window_favicon_callback(hlcache_handle *c, static void browser_window_update_favicon(hlcache_handle *c, struct browser_window *bw, struct content_rfc5988_link *link) { - lwc_string *icon_str; nsurl *nsref = NULL; nsurl *nsurl; nserror error; @@ -979,25 +1017,20 @@ static void browser_window_update_favicon(hlcache_handle *c, bw->failed_favicon = false; if (link == NULL) { - /* look for favicon metadata link */ - if (lwc_intern_string("icon", SLEN("icon"), - &icon_str) == lwc_error_ok) { - link = content_find_rfc5988_link(c, icon_str); - lwc_string_unref(icon_str); - } + /* Look for "icon" */ + link = content_find_rfc5988_link(c, corestring_lwc_icon); } if (link == NULL) { - if (lwc_intern_string("shortcut icon", SLEN("shortcut icon"), - &icon_str) == lwc_error_ok) { - link = content_find_rfc5988_link(c, icon_str); - lwc_string_unref(icon_str); - } + /* Look for "shortcut icon" */ + link = content_find_rfc5988_link(c, + corestring_lwc_shortcut_icon); } if (link == NULL) { lwc_string *scheme; bool speculative_default = false; + bool match; nsurl = hlcache_handle_get_url(c); @@ -1005,12 +1038,10 @@ static void browser_window_update_favicon(hlcache_handle *c, /* If the document was fetched over http(s), then speculate * that there's a favicon living at /favicon.ico */ - if ((lwc_string_length(scheme) == SLEN("HTTP") && - strcasecmp(lwc_string_data(scheme), - "http") == 0) || - (lwc_string_length(scheme) == SLEN("HTTPS") && - strcasecmp(lwc_string_data(scheme), - "https") == 0)) { + if ((lwc_string_caseless_isequal(scheme, corestring_lwc_http, + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(scheme, corestring_lwc_https, + &match) == lwc_error_ok && match)) { speculative_default = true; } @@ -1089,7 +1120,7 @@ static void browser_window_refresh(void *p) nsurl *url; nsurl *refresh; hlcache_handle *parent = NULL; - enum browser_window_nav_flags flags = BROWSER_WINDOW_NONE; + enum browser_window_nav_flags flags = BW_NAVIGATE_UNVERIFIABLE; assert(bw->current_content != NULL && (content_get_status(bw->current_content) == @@ -1108,7 +1139,7 @@ static void browser_window_refresh(void *p) url = hlcache_handle_get_url(bw->current_content); if ((url == NULL) || (nsurl_compare(url, refresh, NSURL_COMPLETE))) { - flags |= BROWSER_WINDOW_HISTORY; + flags |= BW_NAVIGATE_HISTORY; } /* Treat an (almost) immediate refresh in a top-level browser window as @@ -1119,7 +1150,7 @@ static void browser_window_refresh(void *p) * all. */ if (bw->refresh_interval <= 100 && bw->parent == NULL) { - flags |= BROWSER_WINDOW_VERIFIABLE; + flags &= ~BW_NAVIGATE_UNVERIFIABLE; } else { parent = bw->current_content; } @@ -1162,7 +1193,7 @@ static void browser_window_convert_to_download(struct browser_window *bw, /** - * Callback for fetchcache() for browser window fetches. + * Callback handler for content event messages. */ static nserror browser_window_callback(hlcache_handle *c, @@ -1177,9 +1208,7 @@ static nserror browser_window_callback(hlcache_handle *c, browser_window_convert_to_download(bw, event->data.download); if (bw->current_content != NULL) { - browser_window_refresh_url_bar(bw, - hlcache_handle_get_url(bw->current_content), - bw->frag_id); + browser_window_refresh_url_bar(bw); } break; @@ -1227,11 +1256,9 @@ static nserror browser_window_callback(hlcache_handle *c, browser_window_remove_caret(bw, false); if (bw->window != NULL) { - gui_window_new_content(bw->window); + guit->window->new_content(bw->window); - browser_window_refresh_url_bar(bw, - hlcache_handle_get_url(bw->current_content), - bw->frag_id); + browser_window_refresh_url_bar(bw); } /* new content; set scroll_to_top */ @@ -1272,7 +1299,7 @@ static nserror browser_window_callback(hlcache_handle *c, * after, we only leak the thumbnails when urldb does * not add the URL. */ - history_add(bw->history, c, bw->frag_id); + browser_window_history_add(bw, c, bw->frag_id); } /* frames */ @@ -1302,12 +1329,13 @@ static nserror browser_window_callback(hlcache_handle *c, browser_window_stop_throbber(bw); browser_window_update_favicon(c, bw, NULL); - history_update(bw->history, c); + browser_window_history_update(bw, c); hotlist_update_url(hlcache_handle_get_url(c)); - if (bw->refresh_interval != -1) - schedule(bw->refresh_interval, + if (bw->refresh_interval != -1) { + guit->browser->schedule(bw->refresh_interval * 10, browser_window_refresh, bw); + } break; case CONTENT_MSG_ERRORCODE: @@ -1398,34 +1426,17 @@ static nserror browser_window_callback(hlcache_handle *c, case CONTENT_MSG_LINK: /* content has an rfc5988 link element */ { - lwc_string *icon_str; - lwc_string *shortcut_icon_str; - bool icon_match = false; - bool shortcut_icon_match = false; - - if (lwc_intern_string("icon", SLEN("icon"), - &icon_str) == lwc_error_ok) { - if (lwc_string_caseless_isequal( - event->data.rfc5988_link->rel, - icon_str, - &icon_match) != lwc_error_ok) { - icon_match = false; - } - lwc_string_unref(icon_str); - } - - if (lwc_intern_string("shortcut icon", SLEN("shortcut icon"), - &shortcut_icon_str) == lwc_error_ok) { - if (lwc_string_caseless_isequal( - event->data.rfc5988_link->rel, - shortcut_icon_str, - &shortcut_icon_match) != lwc_error_ok) { - shortcut_icon_match = false; - } - lwc_string_unref(shortcut_icon_str); - } - - if (icon_match || shortcut_icon_match) { + bool match; + + /* Handle "icon" and "shortcut icon" */ + if ((lwc_string_caseless_isequal( + event->data.rfc5988_link->rel, + corestring_lwc_icon, + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal( + event->data.rfc5988_link->rel, + corestring_lwc_shortcut_icon, + &match) == lwc_error_ok && match)) { /* it's a favicon perhaps start a fetch for it */ browser_window_update_favicon(c, bw, event->data.rfc5988_link); @@ -1478,20 +1489,23 @@ static nserror browser_window_callback(hlcache_handle *c, switch(event->data.dragsave.type) { case CONTENT_SAVE_ORIG: - gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, save, - root->window); + guit->window->drag_save_object(root->window, save, + GUI_SAVE_OBJECT_ORIG); break; + case CONTENT_SAVE_NATIVE: - gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, save, - root->window); + guit->window->drag_save_object(root->window, save, + GUI_SAVE_OBJECT_NATIVE); break; + case CONTENT_SAVE_COMPLETE: - gui_drag_save_object(GUI_SAVE_COMPLETE, save, - root->window); + guit->window->drag_save_object(root->window, save, + GUI_SAVE_COMPLETE); break; + case CONTENT_SAVE_SOURCE: - gui_drag_save_object(GUI_SAVE_SOURCE, save, - root->window); + guit->window->drag_save_object(root->window, save, + GUI_SAVE_SOURCE); break; } } @@ -1501,7 +1515,7 @@ static nserror browser_window_callback(hlcache_handle *c, { /* Content wants a link to be saved */ struct browser_window *root = browser_window_get_root(bw); - gui_window_save_link(root->window, + guit->window->save_link(root->window, event->data.savelink.url, event->data.savelink.title); } @@ -1555,8 +1569,16 @@ static nserror browser_window_callback(hlcache_handle *c, event->data.selection.read_only); break; + case CONTENT_MSG_GADGETCLICK: + if (event->data.gadget_click.gadget->type == GADGET_FILE) { + guit->window->file_gadget_open(bw->window, c, + event->data.gadget_click.gadget); + } + + break; + default: - assert(0); + break; } return NSERROR_OK; @@ -1604,10 +1626,17 @@ void browser_window_destroy_internal(struct browser_window *bw) LOG(("Destroying window")); - if (bw->children != NULL || bw->iframes != NULL) + if (bw->children != NULL || bw->iframes != NULL) { browser_window_destroy_children(bw); + } - schedule_remove(browser_window_refresh, bw); + /* clear any pending callbacks */ + guit->browser->schedule(-1, browser_window_refresh, bw); + /* The ugly cast here is so the reformat function can be + * passed a gui window pointer in its API rather than void* + */ + LOG(("Clearing schedule %p(%p)", guit->window->reformat, bw->window)); + guit->browser->schedule(-1, (void(*)(void*))guit->window->reformat, bw->window); /* If this brower window is not the root window, and has focus, unset * the root browser window's focus pointer. */ @@ -1629,7 +1658,7 @@ void browser_window_destroy_internal(struct browser_window *bw) if (bw->window) { /* Only the root window has a GUI window */ - gui_window_destroy(bw->window); + guit->window->destroy(bw->window); } if (bw->loading_content != NULL) { @@ -1679,7 +1708,7 @@ void browser_window_destroy_internal(struct browser_window *bw) if (bw->frag_id != NULL) lwc_string_unref(bw->frag_id); - history_destroy(bw->history); + browser_window_history_destroy(bw); free(bw->name); free(bw->status_text); @@ -1705,6 +1734,70 @@ void browser_window_destroy(struct browser_window *bw) } +/** + * Update URL bar for a given browser window to given URL + * + * \param bw Browser window to update URL bar for. + * \param url URL for content displayed by bw including any fragment. + */ + +static inline void browser_window_refresh_url_bar_internal( + struct browser_window *bw, nsurl *url) +{ + assert(bw); + assert(url); + + if (bw->parent != NULL) { + /* Not root window; don't set a URL in GUI URL bar */ + return; + } + + guit->window->set_url(bw->window, nsurl_access(url)); +} + + +/** + * Update URL bar for a given browser window to bw's content's URL + * + * \param bw Browser window to update URL bar for. + */ + +void browser_window_refresh_url_bar(struct browser_window *bw) +{ + assert(bw); + + if (bw->parent != NULL) { + /* Not root window; don't set a URL in GUI URL bar */ + return; + } + + if (bw->current_content == NULL) { + /* TODO: set "about:blank"? */ + return; + } + + if (bw->frag_id == NULL) { + browser_window_refresh_url_bar_internal(bw, + hlcache_handle_get_url(bw->current_content)); + } else { + nsurl *display_url; + nserror error; + + /* Combine URL and Fragment */ + error = nsurl_refragment( + hlcache_handle_get_url(bw->current_content), + bw->frag_id, &display_url); + if (error != NSERROR_OK) { + warn_user("NoMemory", 0); + return; + } + + browser_window_refresh_url_bar_internal(bw, display_url); + nsurl_unref(display_url); + } +} + + /* exported interface documented in desktop/browser.h */ nserror browser_window_navigate(struct browser_window *bw, nsurl *url, @@ -1738,7 +1831,7 @@ nserror browser_window_navigate(struct browser_window *bw, } /* Set up retrieval parameters */ - if ((flags & BROWSER_WINDOW_VERIFIABLE) != 0) { + if (!(flags & BW_NAVIGATE_UNVERIFIABLE)) { fetch_flags |= LLCACHE_RETRIEVE_VERIFIABLE; } @@ -1762,7 +1855,7 @@ nserror browser_window_navigate(struct browser_window *bw, } /* Get download out of the way */ - if ((flags & BROWSER_WINDOW_DOWNLOAD) != 0) { + if ((flags & BW_NAVIGATE_DOWNLOAD) != 0) { error = browser_window_download(bw, url, referrer, @@ -1807,18 +1900,15 @@ nserror browser_window_navigate(struct browser_window *bw, nsurl_unref(referrer); } - if ((flags & BROWSER_WINDOW_HISTORY) != 0) { - history_add(bw->history, + if ((flags & BW_NAVIGATE_HISTORY) != 0) { + browser_window_history_add(bw, bw->current_content, bw->frag_id); } browser_window_update(bw, false); if (bw->current_content != NULL) { - browser_window_refresh_url_bar(bw, - hlcache_handle_get_url( - bw->current_content), - bw->frag_id); + browser_window_refresh_url_bar(bw); } return NSERROR_OK; } @@ -1831,10 +1921,10 @@ nserror browser_window_navigate(struct browser_window *bw, LOG(("Loading '%s'", nsurl_access(url))); browser_window_set_status(bw, messages_get("Loading")); - bw->history_add = (flags & BROWSER_WINDOW_HISTORY); + bw->history_add = (flags & BW_NAVIGATE_HISTORY); /* Verifiable fetches may trigger a download */ - if ((flags & BROWSER_WINDOW_VERIFIABLE) != 0) { + if (!(flags & BW_NAVIGATE_UNVERIFIABLE)) { fetch_flags |= HLCACHE_RETRIEVE_MAY_DOWNLOAD; } @@ -1850,12 +1940,12 @@ nserror browser_window_navigate(struct browser_window *bw, case NSERROR_OK: bw->loading_content = c; browser_window_start_throbber(bw); - browser_window_refresh_url_bar(bw, url, NULL); + browser_window_refresh_url_bar_internal(bw, url); break; case NSERROR_NO_FETCH_HANDLER: /* no handler for this type */ /** @todo does this always try and download even unverifiable content? */ - gui_launch_url(nsurl_access(url)); + error = guit->browser->launch_url(url); break; default: /* report error to user */ @@ -1878,6 +1968,85 @@ nserror browser_window_navigate(struct browser_window *bw, } +/* Exported interface, documented in browser.h */ +nsurl* browser_window_get_url(struct browser_window *bw) +{ + assert(bw != NULL); + + if (bw->current_content != NULL) { + return hlcache_handle_get_url(bw->current_content); + + } else if (bw->loading_content != NULL) { + /* TODO: should we return this? */ + return hlcache_handle_get_url(bw->loading_content); + } + + return corestring_nsurl_about_blank; +} + +/* Exported interface, documented in browser.h */ +const char* browser_window_get_title(struct browser_window *bw) +{ + assert(bw != NULL); + + if (bw->current_content != NULL) { + return content_get_title(bw->current_content); + } + + return NULL; +} + +/* Exported interface, documented in browser.h */ +struct history * browser_window_get_history(struct browser_window *bw) +{ + assert(bw != NULL); + + return bw->history; +} + + +/* Exported interface, documented in browser.h */ +bool browser_window_has_content(struct browser_window *bw) +{ + assert(bw != NULL); + + if (bw->current_content == NULL) { + return false; + } + + return true; +} + +/* Exported interface, documented in browser.h */ +struct hlcache_handle *browser_window_get_content(struct browser_window *bw) +{ + return bw->current_content; +} + +/* Exported interface, documented in browser.h */ +nserror browser_window_get_extents(struct browser_window *bw, bool scaled, + int *width, int *height) +{ + assert(bw != NULL); + + if (bw->current_content == NULL) { + *width = 0; + *height = 0; + return NSERROR_BAD_CONTENT; + } + + *width = content_get_width(bw->current_content); + *height = content_get_height(bw->current_content); + + if (scaled) { + *width *= bw->scale; + *height *= bw->scale; + } + + return NSERROR_OK; +} + + /* * Get the dimensions of the area a browser window occupies * @@ -1898,7 +2067,7 @@ void browser_window_get_dimensions(struct browser_window *bw, *height = bw->height; } else { /* Front end window */ - gui_window_get_dimensions(bw->window, width, height, scaled); + guit->window->get_dimensions(bw->window, width, height, scaled); } } @@ -1945,7 +2114,7 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top) case BROWSER_WINDOW_NORMAL: /* Root browser window, constituting a front end window/tab */ - gui_window_set_title(bw->window, + guit->window->set_title(bw->window, content_get_title(bw->current_content)); browser_window_update_extent(bw); @@ -1960,7 +2129,7 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top) browser_window_set_scroll(bw, x, y); } - gui_window_redraw_window(bw->window); + guit->window->redraw(bw->window); break; @@ -2026,7 +2195,7 @@ void browser_window_update_box(struct browser_window *bw, struct rect *rect) if (bw->window != NULL) { /* Front end window */ - gui_window_update_box(bw->window, rect); + guit->window->update(bw->window, rect); } else { /* Core managed browser window */ browser_window_get_position(bw, true, &pos_x, &pos_y); @@ -2038,7 +2207,7 @@ void browser_window_update_box(struct browser_window *bw, struct rect *rect) rect->x1 += pos_x / bw->scale; rect->y1 += pos_y / bw->scale; - gui_window_update_box(top->window, rect); + guit->window->update(top->window, rect); } } @@ -2068,7 +2237,7 @@ void browser_window_stop(struct browser_window *bw) assert(error == NSERROR_OK); } - schedule_remove(browser_window_refresh, bw); + guit->browser->schedule(-1, browser_window_refresh, bw); if (bw->children) { children = bw->rows * bw->cols; @@ -2082,9 +2251,7 @@ void browser_window_stop(struct browser_window *bw) } if (bw->current_content != NULL) { - browser_window_refresh_url_bar(bw, - hlcache_handle_get_url(bw->current_content), - bw->frag_id); + browser_window_refresh_url_bar(bw); } browser_window_stop_throbber(bw); @@ -2136,7 +2303,7 @@ void browser_window_reload(struct browser_window *bw, bool all) browser_window_navigate(bw, hlcache_handle_get_url(bw->current_content), NULL, - BROWSER_WINDOW_VERIFIABLE, + BW_NAVIGATE_NONE, NULL, NULL, NULL); @@ -2179,7 +2346,7 @@ void browser_window_set_status(struct browser_window *bw, const char *text) } bw->status_miss++; - gui_window_set_status(bw->window, bw->status_text); + guit->window->set_status(bw->window, bw->status_text); } @@ -2221,9 +2388,19 @@ void browser_window_set_pointer(struct browser_window *bw, gui_shape = (gui_pointer_shape)shape; } - gui_window_set_pointer(root->window, gui_shape); + guit->window->set_pointer(root->window, gui_shape); } +/* exported function documented in desktop/browser.h */ +nserror browser_window_schedule_reformat(struct browser_window *bw) +{ + /* The ugly cast here is so the reformat function can be + * passed a gui window pointer in its API rather than void* + */ + LOG(("Scheduleing %p(%p)", guit->window->reformat, bw->window)); + guit->browser->schedule(0, (void(*)(void*))guit->window->reformat, bw->window); + return NSERROR_OK; +} /** * Reformat a browser window contents to a new width or height. @@ -2275,8 +2452,7 @@ static void browser_window_set_scale_internal(struct browser_window *bw, if (content_can_reformat(c) == false) { browser_window_update(bw, false); } else { - bw->reformat_pending = true; - browser_reformat_pending = true; + browser_window_schedule_reformat(bw); } } @@ -2287,14 +2463,7 @@ static void browser_window_set_scale_internal(struct browser_window *bw, } -/** - * Sets the scale of a browser window - * - * \param bw The browser window to scale - * \param scale The new scale - * \param all Scale all windows in the tree (ie work up aswell as down) - */ - +/* exported interface documented in desktop/browser.h */ void browser_window_set_scale(struct browser_window *bw, float scale, bool all) { while (bw->parent && all) @@ -2309,59 +2478,13 @@ void browser_window_set_scale(struct browser_window *bw, float scale, bool all) } -/** - * Gets the scale of a browser window - * - * \param bw The browser window to scale - * \return - */ - +/* exported interface documented in desktop/browser.h */ float browser_window_get_scale(struct browser_window *bw) { return bw->scale; } -/** - * Update URL bar for a given browser window to given URL - * - * \param bw Browser window to update URL bar for. - * \param url URL for content displayed by bw, excluding any fragment. - * \param frag Additional fragment. May be NULL if none. - */ - -void browser_window_refresh_url_bar(struct browser_window *bw, nsurl *url, - lwc_string *frag) -{ - assert(bw); - assert(url); - - if (bw->parent != NULL) { - /* Not root window; don't set a URL in GUI URL bar */ - return; - } - - if (frag == NULL) { - /* With no fragment, we may as well pass url straight through - * saving a malloc, copy, free cycle. - */ - gui_window_set_url(bw->window, nsurl_access(url)); - } else { - nsurl *display_url; - nserror error; - - error = nsurl_refragment(url, frag, &display_url); - if (error != NSERROR_OK) { - warn_user("NoMemory", 0); - return; - } - - gui_window_set_url(bw->window, nsurl_access(display_url)); - nsurl_unref(display_url); - } -} - - static void browser_window_find_target_internal(struct browser_window *bw, const char *target, int depth, struct browser_window *page, int *rdepth, struct browser_window **bw_target) @@ -2462,8 +2585,9 @@ struct browser_window *browser_window_find_target(struct browser_window *bw, * OR * - button_2 opens in new tab and the link target is "_blank" */ - error = browser_window_create(BROWSER_WINDOW_VERIFIABLE | - BROWSER_WINDOW_TAB, + error = browser_window_create(BW_CREATE_TAB | + BW_CREATE_HISTORY | + BW_CREATE_CLONE, NULL, NULL, bw, @@ -2489,7 +2613,8 @@ struct browser_window *browser_window_find_target(struct browser_window *bw, * - button_2 doesn't open in new tabs and the link target is * "_blank" */ - error = browser_window_create(BROWSER_WINDOW_VERIFIABLE, + error = browser_window_create(BW_CREATE_HISTORY | + BW_CREATE_CLONE, NULL, NULL, bw, @@ -2528,7 +2653,7 @@ struct browser_window *browser_window_find_target(struct browser_window *bw, if (!nsoption_bool(target_blank)) return bw; - error = browser_window_create(BROWSER_WINDOW_VERIFIABLE, + error = browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY, NULL, NULL, bw, @@ -2879,14 +3004,14 @@ void browser_window_mouse_click(struct browser_window *bw, break; default: if (mouse & BROWSER_MOUSE_MOD_2) { - if (mouse & BROWSER_MOUSE_DRAG_2) - gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, c, - bw->window); - else if (mouse & BROWSER_MOUSE_DRAG_1) - gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, c, - bw->window); - } - else if (mouse & (BROWSER_MOUSE_DRAG_1 | + if (mouse & BROWSER_MOUSE_DRAG_2) { + guit->window->drag_save_object(bw->window, c, + GUI_SAVE_OBJECT_NATIVE); + } else if (mouse & BROWSER_MOUSE_DRAG_1) { + guit->window->drag_save_object(bw->window, c, + GUI_SAVE_OBJECT_ORIG); + } + } else if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { browser_window_page_drag_start(bw, x, y); browser_window_set_pointer(bw, BROWSER_POINTER_MOVE); @@ -2932,10 +3057,10 @@ void browser_window_page_drag_start(struct browser_window *bw, int x, int y) if (bw->window != NULL) { /* Front end window */ - gui_window_get_scroll(bw->window, &bw->drag_start_scroll_x, + guit->window->get_scroll(bw->window, &bw->drag_start_scroll_x, &bw->drag_start_scroll_y); - gui_window_scroll_start(bw->window); + guit->window->scroll_start(bw->window); } else { /* Core managed browser window */ bw->drag_start_scroll_x = scrollbar_get_offset(bw->scroll_x); @@ -2953,7 +3078,8 @@ void browser_window_page_drag_start(struct browser_window *bw, int x, int y) bool browser_window_back_available(struct browser_window *bw) { - return (bw && bw->history && history_back_available(bw->history)); + return (bw && bw->history && + browser_window_history_back_available(bw)); } @@ -2966,7 +3092,8 @@ bool browser_window_back_available(struct browser_window *bw) bool browser_window_forward_available(struct browser_window *bw) { - return (bw && bw->history && history_forward_available(bw->history)); + return (bw && bw->history && + browser_window_history_forward_available(bw)); } diff --git a/desktop/browser.h b/desktop/browser.h index ee55e72c4..c7d8b7e79 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -25,12 +25,13 @@ #define _NETSURF_DESKTOP_BROWSER_H_ #include <stdbool.h> +#include <stdio.h> -#include "content/content.h" +#include "utils/types.h" +#include "utils/errors.h" +#include "desktop/plot_style.h" #include "desktop/frame_types.h" -#include "desktop/gui.h" #include "desktop/mouse.h" -#include "utils/types.h" struct browser_window; @@ -39,7 +40,9 @@ struct gui_window; struct history; struct selection; struct fetch_multipart_data; - +struct form_control; +struct nsurl; +enum content_debug; typedef enum { DRAGGING_NONE, @@ -59,39 +62,69 @@ typedef enum { BW_EDITOR_CAN_PASTE = (1 << 2) /**< Can paste, input */ } browser_editor_flags; -extern bool browser_reformat_pending; +/** flags to browser_window_create */ +enum browser_window_create_flags { + /** No flags set */ + BW_CREATE_NONE = 0, -/** flags to browser window go */ + /** this will form a new history node (don't set for back/reload/etc) */ + BW_CREATE_HISTORY = (1 << 0), + + /** New gui_window to be tab in same window as "existing" gui_window */ + BW_CREATE_TAB = (1 << 1), + + /** New gui_window to be clone of "existing" gui_window */ + BW_CREATE_CLONE = (1 << 2), + + /** Window not opened by user interaction (e.g. JS popup) + * + * rfc2965: + * A transaction is verifiable if the user, or a + * user-designated agent, has the option to review + * the request-URI prior to its use in the transaction. + * A transaction is unverifiable if the user does not + * have that option. + */ + BW_CREATE_UNVERIFIABLE = (1 << 3), +}; + +/** flags to browser_window_navigate */ enum browser_window_nav_flags { - BROWSER_WINDOW_NONE = 0, + /** No flags set */ + BW_NAVIGATE_NONE = 0, + /** this will form a new history node (don't set for back/reload/etc) */ - BROWSER_WINDOW_HISTORY = 1, + BW_NAVIGATE_HISTORY = (1 << 0), + /** download rather than render the uri */ - BROWSER_WINDOW_DOWNLOAD = 2, - /** this transaction is verifiable */ - BROWSER_WINDOW_VERIFIABLE = 4, - /** open a new tab rather than a new window */ - BROWSER_WINDOW_TAB = 8, + BW_NAVIGATE_DOWNLOAD = (1 << 1), + + /** Transation not caused by user interaction (e.g. JS-caused) + * + * rfc2965: + * A transaction is verifiable if the user, or a + * user-designated agent, has the option to review + * the request-URI prior to its use in the transaction. + * A transaction is unverifiable if the user does not + * have that option. + */ + BW_NAVIGATE_UNVERIFIABLE = (1 << 2) }; -void browser_window_initialise_common(struct browser_window *bw, - struct browser_window *clone); - /** * Create and open a new root browser window with the given page. * - * \param flags Flags to control operation - * \param url URL to start fetching in the new window or NULL for blank - * \param referer The referring uri or NULL if none - * \param clone The browser window to clone - * \param bw pointer to created browser window or untouched on error. - * \return error code + * \param flags Flags to control operation + * \param url URL to fetch in the new window or NULL for blank + * \param referer The referring uri or NULL if none + * \param existing The an existing bw or NULL, required for some flags. + * \param bw Updated to created browser window or untouched on error. + * \return NSERROR_OK, or appropriate error otherwise. */ -nserror browser_window_create(enum browser_window_nav_flags flags, - nsurl *url, - nsurl *referrer, - struct browser_window *clone, - struct browser_window **bw); +nserror browser_window_create(enum browser_window_create_flags flags, + struct nsurl *url, struct nsurl *referrer, + struct browser_window *existing, + struct browser_window **bw); /** * Start fetching a page in a browser window. @@ -111,12 +144,64 @@ nserror browser_window_create(enum browser_window_nav_flags flags, * */ nserror browser_window_navigate(struct browser_window *bw, - nsurl *url, - nsurl *referrer, + struct nsurl *url, + struct nsurl *referrer, enum browser_window_nav_flags flags, char *post_urlenc, struct fetch_multipart_data *post_multipart, - hlcache_handle *parent); + struct hlcache_handle *parent); + +/** + * Get a browser window's URL. + * + * \param bw browser window + * \return pointer to nsurl. Doesn't create a ref for caller. + * + * Note: guaranteed to return a valid nsurl ptr, never returns NULL. + */ +struct nsurl* browser_window_get_url(struct browser_window *bw); + +/** + * Get the title of a browser_window. + * + * \param bw The browser window. + */ +const char* browser_window_get_title(struct browser_window *bw); + +/** + * Get a browser window's history object. + * + * \param bw browser window + * \return pointer browser window's history object + * + * Clients need history object to make use of the history_* functions. + */ +struct history * browser_window_get_history(struct browser_window *bw); + +/** + * Get a browser window's content extents. + * + * \param bw browser window + * \param scaled whether to apply current browser window scale + * \param width updated to content width extent in px + * \param width updated to content height extent in px + * \return NSERROR_OK, or appropriate error otherwise. + */ +nserror browser_window_get_extents(struct browser_window *bw, bool scaled, + int *width, int *height); + +/** + * Find out if a browser window is currently showing a content. + * + * \param bw browser window + * \return true iff browser window is showing a content, else false. + */ +bool browser_window_has_content(struct browser_window *bw); + +/** + * Get a cache handle for the content within a browser window. + */ +struct hlcache_handle *browser_window_get_content(struct browser_window *bw); void browser_window_get_dimensions(struct browser_window *bw, int *width, int *height, bool scaled); @@ -129,7 +214,24 @@ void browser_window_reload(struct browser_window *bw, bool all); void browser_window_destroy(struct browser_window *bw); void browser_window_reformat(struct browser_window *bw, bool background, int width, int height); + + +/** + * Sets the scale of a browser window. + * + * \param bw The browser window to scale. + * \param scale The new scale. + * \param all Scale all windows in the tree (ie work up aswell as down) + */ void browser_window_set_scale(struct browser_window *bw, float scale, bool all); + + +/** + * Gets the scale of a browser window + * + * \param bw The browser window to get the scale of. + * \return The scale of teh window. + */ float browser_window_get_scale(struct browser_window *bw); /** @@ -173,8 +275,10 @@ bool browser_window_scroll_at_point(struct browser_window *bw, bool browser_window_drop_file_at_point(struct browser_window *bw, int x, int y, char *file); -void browser_window_refresh_url_bar(struct browser_window *bw, nsurl *url, - lwc_string *frag); +void browser_window_set_gadget_filename(struct browser_window *bw, + struct form_control *gadget, const char *fn); + +void browser_window_refresh_url_bar(struct browser_window *bw); void browser_window_mouse_click(struct browser_window *bw, browser_mouse_state mouse, int x, int y); @@ -184,6 +288,21 @@ struct browser_window *browser_window_find_target( struct browser_window *bw, const char *target, browser_mouse_state mouse); +/** + * Cause the frontends reformat entry to be called in safe context. + * + * The browser_window_reformat call cannot safely be called from some + * contexts, this call allows for the reformat to happen from a safe + * top level context. + * + * The callback is frontend provided as the context information (size + * etc.) about the windowing toolkit is only available to the + * frontend. + */ +nserror browser_window_schedule_reformat(struct browser_window *bw); + + + void browser_select_menu_callback(void *client_data, int x, int y, int width, int height); @@ -240,15 +359,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, */ bool browser_window_redraw_ready(struct browser_window *bw); -/* - * Update the extent of the inside of a browser window to that of the current - * content - * - * \param bw browser_window to update the extent of - */ -void browser_window_update_extent(struct browser_window *bw); - -/* +/** * Get the position of the current browser window with respect to the root or * parent browser window * @@ -260,7 +371,7 @@ void browser_window_update_extent(struct browser_window *bw); void browser_window_get_position(struct browser_window *bw, bool root, int *pos_x, int *pos_y); -/* +/** * Set the position of the current browser window with respect to the parent * browser window * @@ -270,7 +381,7 @@ void browser_window_get_position(struct browser_window *bw, bool root, */ void browser_window_set_position(struct browser_window *bw, int x, int y); -/* +/** * Scroll the browser window to display the passed area * * \param bw browser window to scroll @@ -291,7 +402,7 @@ void browser_window_scroll_visible(struct browser_window *bw, */ void browser_window_set_scroll(struct browser_window *bw, int x, int y); -/* +/** * Set drag type for a browser window, and inform front end * * \param bw browser window to set the type of the current drag for @@ -301,7 +412,7 @@ void browser_window_set_scroll(struct browser_window *bw, int x, int y); void browser_window_set_drag_type(struct browser_window *bw, browser_drag_type type, const struct rect *rect); -/* +/** * Get type of any current drag for a browser window * * \param bw browser window to set the type of the current drag for @@ -309,7 +420,7 @@ void browser_window_set_drag_type(struct browser_window *bw, */ browser_drag_type browser_window_get_drag_type(struct browser_window *bw); -/* +/** * Get the root level browser window * * \param bw browser window to set the type of the current drag for @@ -342,7 +453,7 @@ char * browser_window_get_selection(struct browser_window *bw); * \param bw The browser window * \param f The file to dump to */ -void browser_window_debug_dump(struct browser_window *bw, FILE *f); +nserror browser_window_debug_dump(struct browser_window *bw, FILE *f, enum content_debug op); /* In platform specific theme_install.c. */ #ifdef WITH_THEME_INSTALL diff --git a/desktop/local_history.c b/desktop/browser_history.c index d4ecfd3bb..8c21eed8e 100644 --- a/desktop/local_history.c +++ b/desktop/browser_history.c @@ -26,13 +26,13 @@ #include <stdlib.h> #include <string.h> #include <time.h> + #include "content/content.h" #include "content/hlcache.h" #include "content/urldb.h" #include "css/css.h" -#include "desktop/browser.h" -#include "desktop/gui.h" -#include "desktop/local_history.h" +#include "desktop/browser_history.h" +#include "desktop/browser_private.h" #include "desktop/plotters.h" #include "desktop/thumbnail.h" #include "image/bitmap.h" @@ -80,75 +80,6 @@ struct history { int height; }; -static struct history_entry *history_clone_entry(struct history *history, - struct history_entry *entry); -static void history_free_entry(struct history_entry *entry); -static void history_layout(struct history *history); -static int history_layout_subtree(struct history *history, - struct history_entry *entry, int x, int y, bool shuffle); -static bool 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); -static struct history_entry *history_find_position(struct history_entry *entry, - int x, int y); -static bool history_enumerate_entry(const struct history *history, - const struct history_entry *entry, history_enumerate_cb cb, void *ud); - - -/** - * Create a new history tree for a window. - * - * \return pointer to an opaque history structure, 0 on failure. - */ - -struct history *history_create(void) -{ - struct history *history; - - history = calloc(1, sizeof *history); - if (!history) { - warn_user("NoMemory", 0); - return 0; - } - history->width = RIGHT_MARGIN / 2; - history->height = BOTTOM_MARGIN / 2; - return history; -} - - -/** - * Clone a history tree - * - * \param history opaque history structure, as returned by history_create() - * - * \return pointer to an opaque history structure, 0 on failure. - */ - -struct history *history_clone(struct history *history) -{ - struct history *new_history; - - if (!history->start) - return history_create(); - - new_history = malloc(sizeof *history); - if (!new_history) - return 0; - memcpy(new_history, history, sizeof *history); - - new_history->start = history_clone_entry(new_history, - new_history->start); - if (!history->start) { - LOG(("Insufficient memory to clone history")); - warn_user("NoMemory", 0); - history_destroy(new_history); - return 0; - } - - return new_history; -} - /** * Clone a history entry @@ -159,7 +90,8 @@ struct history *history_clone(struct history *history) * \return a cloned history entry, or 0 on error */ -struct history_entry *history_clone_entry(struct history *history, +static struct history_entry *browser_window_history__clone_entry( + struct history *history, struct history_entry *entry) { struct history_entry *child; @@ -197,7 +129,7 @@ struct history_entry *history_clone_entry(struct history *history, /* recurse for all children */ for (child = new_entry->forward; child; child = child->next) { - new_child = history_clone_entry(history, child); + new_child = browser_window_history__clone_entry(history, child); if (new_child) { new_child->back = new_entry; } else { @@ -223,26 +155,360 @@ struct history_entry *history_clone_entry(struct history *history, /** + * Free an entry in the tree recursively. + */ + +static void browser_window_history__free_entry(struct history_entry *entry) +{ + if (!entry) + return; + browser_window_history__free_entry(entry->forward); + browser_window_history__free_entry(entry->next); + nsurl_unref(entry->page.url); + if (entry->page.frag_id) + lwc_string_unref(entry->page.frag_id); + free(entry->page.title); + free(entry); +} + + +/** + * Recursively position a subtree. + * + * \param history history being laid out + * \param entry subtree to position + * \param x x position for entry + * \param y smallest available y + * \param shuffle shuffle layout + * \return greatest y used by subtree + */ + +static int browser_window_history__layout_subtree(struct history *history, + struct history_entry *entry, int x, int y, bool shuffle) +{ + struct history_entry *child; + int y1 = y; + + if (history->width < x + WIDTH) + history->width = x + WIDTH; + + if (!entry->forward) { + entry->x = x; + entry->y = y; + if (shuffle) { + entry->x = rand() % 600; + entry->y = rand() % 400; + } + return y + HEIGHT; + } + + /* layout child subtrees below each other */ + for (child = entry->forward; child; child = child->next) { + y1 = browser_window_history__layout_subtree(history, child, + x + WIDTH + RIGHT_MARGIN, y1, shuffle); + if (child->next) + y1 += BOTTOM_MARGIN; + } + + /* place ourselves in the middle */ + entry->x = x; + entry->y = (y + y1) / 2 - HEIGHT / 2; + if (shuffle) { + entry->x = rand() % 600; + entry->y = rand() % 400; + } + + return y1; +} + + +/** + * Compute node positions. + * + * \param history history to layout + * + * Each node's x and y are filled in. + */ + +static void browser_window_history__layout(struct history *history) +{ + time_t t = time(0); + struct tm *tp = localtime(&t); + bool shuffle = tp->tm_mon == 3 && tp->tm_mday == 1; + + if (!history) + return; + + history->width = 0; + if (history->start) + history->height = browser_window_history__layout_subtree( + history, history->start, + RIGHT_MARGIN / 2, BOTTOM_MARGIN / 2, + shuffle); + else + history->height = 0; + if (shuffle) { + history->width = 600 + WIDTH; + history->height = 400 + HEIGHT; + } + history->width += RIGHT_MARGIN / 2; + history->height += BOTTOM_MARGIN / 2; +} + +/** + * Recursively redraw a history_entry. + * + * \param history history containing the entry + * \param history_entry entry to render + * \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) +{ + const struct plotter_table *plot = ctx->plot; + size_t char_offset; + int actual_x; + struct history_entry *child; + colour c = entry == history->current ? + HISTORY_COLOUR_SELECTED : HISTORY_COLOUR_FOREGROUND; + int tailsize = 5; + int xoffset = x - x0; + int yoffset = y - y0; + plot_style_t pstyle_history_rect = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_colour = c, + .stroke_width = entry == history->current ? 3 : 1, + }; + plot_font_style_t fstyle = *plot_style_font; + + if (clip) { + struct rect rect; + rect.x0 = x0 + xoffset; + rect.y0 = y0 + yoffset; + rect.x1 = x1 + xoffset; + rect.y1 = y1 + yoffset; + if(!plot->clip(&rect)) + return false; + } + + if (!plot->bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT, + entry->bitmap, 0xffffff, 0)) + return false; + if (!plot->rectangle(entry->x - 1 + xoffset, + entry->y - 1 + yoffset, + entry->x + xoffset + WIDTH, + entry->y + yoffset + HEIGHT, + &pstyle_history_rect)) + return false; + + if (!nsfont.font_position_in_string(plot_style_font, entry->page.title, + strlen(entry->page.title), WIDTH, + &char_offset, &actual_x)) + return false; + + fstyle.background = HISTORY_COLOUR_BACKGROUND; + fstyle.foreground = c; + fstyle.weight = entry == history->current ? 900 : 400; + + if (!plot->text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset, + entry->page.title, char_offset, &fstyle)) + return false; + + for (child = entry->forward; child; child = child->next) { + if (!plot->line(entry->x + WIDTH + xoffset, + entry->y + HEIGHT / 2 + yoffset, + entry->x + WIDTH + tailsize + xoffset, + entry->y + HEIGHT / 2 + yoffset, + plot_style_stroke_history)) + return false; + if (!plot->line(entry->x + WIDTH + tailsize + xoffset, + entry->y + HEIGHT / 2 + yoffset, + child->x - tailsize +xoffset, + child->y + HEIGHT / 2 + yoffset, + plot_style_stroke_history)) + return false; + if (!plot->line(child->x - tailsize + xoffset, + child->y + HEIGHT / 2 + yoffset, + child->x + xoffset, child->y + + HEIGHT / 2 + yoffset, + plot_style_stroke_history)) + 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 + * See also history_enumerate() + * + * \param bw The browser window to enumerate history of + * \param entry entry to start enumeration at + * \param cb callback function + * \param ud context pointer passed to cb + * \return true to continue enumeration, false to cancel + */ +static bool browser_window_history__enumerate_entry( + const struct browser_window *bw, + const struct history_entry *entry, + browser_window_history_enumerate_cb cb, + void *ud) +{ + const struct history_entry *child; + + if (!cb(bw, entry->x, entry->y, + entry->x + WIDTH, entry->y + HEIGHT, + entry, ud)) + return false; + + for (child = entry->forward; child; child = child->next) { + if (!browser_window_history__enumerate_entry(bw, child, + cb, ud)) + return false; + } + + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +/** + * 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) +{ + struct history *history; + + bw->history = NULL; + + history = calloc(1, sizeof *history); + if (!history) { + warn_user("NoMemory", 0); + return NSERROR_NOMEM; + } + history->width = RIGHT_MARGIN / 2; + history->height = BOTTOM_MARGIN / 2; + + bw->history = history; + return NSERROR_OK; +} + + +/** + * 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) +{ + struct history *new_history; + + clone->history = NULL; + + if (existing == NULL || existing->history == NULL || + existing->history->start == NULL) + /* Nothing to clone, create new history for clone window */ + return browser_window_history_create(clone); + + /* Make cloned history */ + new_history = malloc(sizeof *new_history); + if (!new_history) + return NSERROR_NOMEM; + + clone->history = new_history; + memcpy(new_history, existing->history, sizeof *new_history); + + new_history->start = browser_window_history__clone_entry(new_history, + new_history->start); + if (!new_history->start) { + LOG(("Insufficient memory to clone history")); + warn_user("NoMemory", 0); + browser_window_history_destroy(clone); + clone->history = NULL; + return NSERROR_NOMEM; + } + + return NSERROR_OK; +} + + +/** * Insert a url into the history tree. * - * \param history opaque history structure, as returned by history_create() + * \param bw browser window with history object * \param content content to add to history * \param frag_id fragment identifier, or NULL. * * The page is added after the current entry and becomes current. */ -void history_add(struct history *history, hlcache_handle *content, - lwc_string *frag_id) + +void browser_window_history_add(struct browser_window *bw, + struct hlcache_handle *content, lwc_string *frag_id) { + struct history *history; struct history_entry *entry; nsurl *nsurl = hlcache_handle_get_url(content); char *title; struct bitmap *bitmap; - assert(history); + assert(bw); + assert(bw->history); assert(content); + history = bw->history; + /* allocate space */ entry = malloc(sizeof *entry); if (entry == NULL) @@ -297,7 +563,7 @@ void history_add(struct history *history, hlcache_handle *content, } entry->bitmap = bitmap; - history_layout(history); + browser_window_history__layout(history); } @@ -308,10 +574,16 @@ void history_add(struct history *history, hlcache_handle *content, * \param content content for current entry */ -void history_update(struct history *history, hlcache_handle *content) +void browser_window_history_update(struct browser_window *bw, + struct hlcache_handle *content) { + struct history *history; char *title; + assert(bw != NULL); + + history = bw->history; + if (!history || !history->current || !history->current->bitmap) return; @@ -338,30 +610,17 @@ void history_update(struct history *history, hlcache_handle *content) * \param history opaque history structure, as returned by history_create() */ -void history_destroy(struct history *history) +void browser_window_history_destroy(struct browser_window *bw) { - if (!history) + assert(bw != NULL); + + if (bw->history == NULL) return; - history_free_entry(history->start); - free(history); -} + browser_window_history__free_entry(bw->history->start); + free(bw->history); -/** - * Free an entry in the tree recursively. - */ - -void history_free_entry(struct history_entry *entry) -{ - if (!entry) - return; - history_free_entry(entry->forward); - history_free_entry(entry->next); - nsurl_unref(entry->page.url); - if (entry->page.frag_id) - lwc_string_unref(entry->page.frag_id); - free(entry->page.title); - free(entry); + bw->history = NULL; } @@ -370,13 +629,15 @@ void history_free_entry(struct history_entry *entry) * * \param bw browser window * \param history history of the window + * \param new_window whether to open in new window */ -void history_back(struct browser_window *bw, struct history *history) +void browser_window_history_back(struct browser_window *bw, bool new_window) { - if (!history || !history->current || !history->current->back) + if (!bw || !bw->history || !bw->history->current || + !bw->history->current->back) return; - history_go(bw, history, history->current->back, false); + browser_window_history_go(bw, bw->history->current->back, new_window); } @@ -385,13 +646,16 @@ void history_back(struct browser_window *bw, struct history *history) * * \param bw browser window * \param history history of the window + * \param new_window whether to open in new window */ -void history_forward(struct browser_window *bw, struct history *history) +void browser_window_history_forward(struct browser_window *bw, bool new_window) { - if (!history || !history->current || !history->current->forward_pref) + if (!bw || !bw->history || !bw->history->current || + !bw->history->current->forward_pref) return; - history_go(bw, history, history->current->forward_pref, false); + browser_window_history_go(bw, bw->history->current->forward_pref, + new_window); } @@ -402,9 +666,10 @@ void history_forward(struct browser_window *bw, struct history *history) * \return true if the history can go back, false otherwise */ -bool history_back_available(struct history *history) +bool browser_window_history_back_available(struct browser_window *bw) { - return (history && history->current && history->current->back); + return (bw && bw->history && bw->history->current && + bw->history->current->back); } @@ -415,25 +680,24 @@ bool history_back_available(struct history *history) * \return true if the history can go forwards, false otherwise */ -bool history_forward_available(struct history *history) +bool browser_window_history_forward_available(struct browser_window *bw) { - return (history && history->current && history->current->forward_pref); + return (bw && bw->history && bw->history->current && + bw->history->current->forward_pref); } /* Documented in local_history.h */ -void history_go(struct browser_window *bw, - struct history *history, - struct history_entry *entry, - bool new_window) +void browser_window_history_go(struct browser_window *bw, + struct history_entry *entry, bool new_window) { + struct history *history; nsurl *url; struct history_entry *current; nserror error; -// LOG(("%p %p %p", bw, history, entry)); -// LOG(("%s %s %s", -// entry->page.url, entry->page.title, entry->page.frag_id)); + assert(bw != NULL); + history = bw->history; if (entry->page.frag_id) { error = nsurl_refragment(entry->page.url, @@ -451,16 +715,17 @@ void history_go(struct browser_window *bw, current = history->current; history->current = entry; - browser_window_create(BROWSER_WINDOW_VERIFIABLE, - url, - NULL, - bw, - NULL); + error = browser_window_create(BW_CREATE_CLONE, + url, NULL, bw, NULL); history->current = current; + if (error != NSERROR_OK) { + nsurl_unref(url); + return; + } } else { history->current = entry; browser_window_navigate(bw, url, NULL, - BROWSER_WINDOW_VERIFIABLE, NULL, NULL, NULL); + BW_NAVIGATE_NONE, NULL, NULL, NULL); } nsurl_unref(url); @@ -468,89 +733,6 @@ void history_go(struct browser_window *bw, /** - * Compute node positions. - * - * \param history history to layout - * - * Each node's x and y are filled in. - */ - -void history_layout(struct history *history) -{ - time_t t = time(0); - struct tm *tp = localtime(&t); - bool shuffle = tp->tm_mon == 3 && tp->tm_mday == 1; - - if (!history) - return; - - history->width = 0; - if (history->start) - history->height = history_layout_subtree(history, - history->start, RIGHT_MARGIN / 2, BOTTOM_MARGIN / 2, - shuffle); - else - history->height = 0; - if (shuffle) { - history->width = 600 + WIDTH; - history->height = 400 + HEIGHT; - } - history->width += RIGHT_MARGIN / 2; - history->height += BOTTOM_MARGIN / 2; -} - - -/** - * Recursively position a subtree. - * - * \param history history being laid out - * \param entry subtree to position - * \param x x position for entry - * \param y smallest available y - * \param shuffle shuffle layout - * \return greatest y used by subtree - */ - -int history_layout_subtree(struct history *history, - struct history_entry *entry, int x, int y, bool shuffle) -{ - struct history_entry *child; - int y1 = y; - - if (history->width < x + WIDTH) - history->width = x + WIDTH; - - if (!entry->forward) { - entry->x = x; - entry->y = y; - if (shuffle) { - entry->x = rand() % 600; - entry->y = rand() % 400; - } - return y + HEIGHT; - } - - /* layout child subtrees below each other */ - for (child = entry->forward; child; child = child->next) { - y1 = history_layout_subtree(history, child, - x + WIDTH + RIGHT_MARGIN, y1, shuffle); - if (child->next) - y1 += BOTTOM_MARGIN; - } - - /* place ourselves in the middle */ - entry->x = x; - entry->y = (y + y1) / 2 - HEIGHT / 2; - if (shuffle) { - entry->x = rand() % 600; - entry->y = rand() % 400; - } - - return y1; -} - - -/** * Get the dimensions of a history. * * \param history history to measure @@ -558,10 +740,14 @@ int history_layout_subtree(struct history *history, * \param height updated to height */ -void history_size(struct history *history, int *width, int *height) +void browser_window_history_size(struct browser_window *bw, + int *width, int *height) { - *width = history->width; - *height = history->height; + assert(bw != NULL); + assert(bw->history != NULL); + + *width = bw->history->width; + *height = bw->history->height; } @@ -572,12 +758,18 @@ void history_size(struct history *history, int *width, int *height) * \param ctx current redraw context */ -bool history_redraw(struct history *history, const struct redraw_context *ctx) +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->start) return true; - return history_redraw_entry(history, history->start, 0, 0, 0, 0, 0, 0, - false, ctx); + return browser_window_history__redraw_entry(history, history->start, + 0, 0, 0, 0, 0, 0, false, ctx); } /** @@ -593,127 +785,48 @@ bool history_redraw(struct history *history, const struct redraw_context *ctx) * \param ctx current redraw context */ -bool history_redraw_rectangle(struct history *history, +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 history_redraw_entry(history, history->start, + return browser_window_history__redraw_entry(history, history->start, x0, y0, x1, y1, x, y, true, ctx); } -/** - * Recursively redraw a history_entry. - * - * \param history history containing the entry - * \param history_entry entry to render - * \param ctx current redraw context - */ - -bool 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) -{ - const struct plotter_table *plot = ctx->plot; - size_t char_offset; - int actual_x; - struct history_entry *child; - colour c = entry == history->current ? HISTORY_COLOUR_SELECTED : HISTORY_COLOUR_FOREGROUND; - int tailsize = 5; - int xoffset = x - x0; - int yoffset = y - y0; - plot_style_t pstyle_history_rect = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_colour = c, - .stroke_width = entry == history->current ? 3 : 1, - }; - plot_font_style_t fstyle = *plot_style_font; - - if (clip) { - struct rect rect; - rect.x0 = x0 + xoffset; - rect.y0 = y0 + yoffset; - rect.x1 = x1 + xoffset; - rect.y1 = y1 + yoffset; - if(!plot->clip(&rect)) - return false; - } - - if (!plot->bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT, - entry->bitmap, 0xffffff, 0)) - return false; - if (!plot->rectangle(entry->x - 1 + xoffset, - entry->y - 1 + yoffset, - entry->x + xoffset + WIDTH, - entry->y + yoffset + HEIGHT, - &pstyle_history_rect)) - return false; - - if (!nsfont.font_position_in_string(plot_style_font, entry->page.title, - strlen(entry->page.title), WIDTH, - &char_offset, &actual_x)) - return false; - - fstyle.background = HISTORY_COLOUR_BACKGROUND; - fstyle.foreground = c; - fstyle.weight = entry == history->current ? 900 : 400; - - if (!plot->text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset, - entry->page.title, char_offset, &fstyle)) - return false; - - for (child = entry->forward; child; child = child->next) { - if (!plot->line(entry->x + WIDTH + xoffset, - entry->y + HEIGHT / 2 + yoffset, - entry->x + WIDTH + tailsize + xoffset, - entry->y + HEIGHT / 2 + yoffset, - plot_style_stroke_history)) - return false; - if (!plot->line(entry->x + WIDTH + tailsize + xoffset, - entry->y + HEIGHT / 2 + yoffset, - child->x - tailsize +xoffset, - child->y + HEIGHT / 2 + yoffset, - plot_style_stroke_history)) - return false; - if (!plot->line(child->x - tailsize + xoffset, - child->y + HEIGHT / 2 + yoffset, - child->x + xoffset, child->y + HEIGHT / 2 + yoffset, - plot_style_stroke_history)) - return false; - if (!history_redraw_entry(history, child, x0, y0, x1, y1, x, y, - clip, ctx)) - return false; - } - - return true; -} - /** * Handle a mouse click in a history. * * \param bw browser window containing history - * \param history history that was clicked in * \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 history_click(struct browser_window *bw, struct history *history, +bool browser_window_history_click(struct browser_window *bw, int x, int y, bool new_window) { struct history_entry *entry; + struct history *history; - entry = history_find_position(history->start, x, y); + 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; - history_go(bw, history, entry, new_window); + browser_window_history_go(bw, entry, new_window); return true; } @@ -728,126 +841,82 @@ bool history_click(struct browser_window *bw, struct history *history, * \return URL, or 0 if no entry at (x, y) */ -const char *history_position_url(struct history *history, int x, int y) +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 = history_find_position(history->start, x, y); + entry = browser_window_history__find_position(history->start, x, y); if (!entry) return 0; return nsurl_access(entry->page.url); } - -/** - * 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 - */ - -struct history_entry *history_find_position(struct history_entry *entry, - int x, int y) +/* Documented in local_history.h */ +void browser_window_history_enumerate_forward(const struct browser_window *bw, + browser_window_history_enumerate_cb cb, void *user_data) { - 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; + struct history_entry *e; - for (child = entry->forward; child; child = child->next) { - found = history_find_position(child, x, y); - if (found) - return found; - } - - return 0; -} + if (bw == NULL || bw->history == NULL || bw->history->current == NULL) + return; -/* Documented in local_history.h */ -void history_enumerate_forward(struct history *history, - history_enumerate_cb cb, void *user_data) -{ - struct history_entry *entry; - - if (history == NULL || history->current == NULL) return; - - for (entry = history->current->forward_pref; entry != NULL; entry = entry->forward_pref) { - if (!cb(history, entry->x, entry->y, entry->x + WIDTH, - entry->y + HEIGHT, entry, user_data)) + e = bw->history->current->forward_pref; + for (; e != NULL; e = e->forward_pref) { + if (!cb(bw, e->x, e->y, e->x + WIDTH, e->y + HEIGHT, + e, user_data)) break; } } /* Documented in local_history.h */ -void history_enumerate_back(struct history *history, - history_enumerate_cb cb, void *user_data) +void browser_window_history_enumerate_back(const struct browser_window *bw, + browser_window_history_enumerate_cb cb, void *user_data) { - struct history_entry *entry; - - if (history == NULL || history->current == NULL) return; - - for (entry = history->current->back; entry != NULL; entry = entry->back) { - if (!cb(history, entry->x, entry->y, entry->x + WIDTH, - entry->y + HEIGHT, entry, user_data)) + struct history_entry *e; + + if (bw == NULL || bw->history == NULL || bw->history->current == NULL) + return; + + for (e = bw->history->current->back; e != NULL; e = e->back) { + if (!cb(bw, e->x, e->y, e->x + WIDTH, e->y + HEIGHT, + e, user_data)) break; } } /* Documented in local_history.h */ -void history_enumerate(const struct history *history, history_enumerate_cb cb, - void *user_data) +void browser_window_history_enumerate(const struct browser_window *bw, + browser_window_history_enumerate_cb cb, void *user_data) { - history_enumerate_entry(history, history->start, cb, user_data); -} - -/** - * Enumerate subentries in history - * See also history_enumerate() - * - * \param history history to enumerate - * \param entry entry to start enumeration at - * \param cb callback function - * \param ud context pointer passed to cb - * \return true to continue enumeration, false to cancel - */ -static bool history_enumerate_entry(const struct history *history, - const struct history_entry *entry, history_enumerate_cb cb, void *ud) -{ - const struct history_entry *child; - - if (!cb(history, entry->x, entry->y, entry->x + WIDTH, entry->y + HEIGHT, - entry, ud)) return false; - - for (child = entry->forward; child; child = child->next) { - if (!history_enumerate_entry(history, child, cb, ud)) - return false; - } - - return true; + if (bw == NULL || bw->history == NULL) + return; + browser_window_history__enumerate_entry(bw, + bw->history->start, cb, user_data); } /* Documented in local_history.h */ -const char *history_entry_get_url(const struct history_entry *entry) +const char *browser_window_history_entry_get_url( + const struct history_entry *entry) { return nsurl_access(entry->page.url); } /* Documented in local_history.h */ -const char *history_entry_get_fragment_id(const struct history_entry *entry) +const char *browser_window_history_entry_get_fragment_id( + const struct history_entry *entry) { return (entry->page.frag_id) ? lwc_string_data(entry->page.frag_id) : 0; } /* Documented in local_history.h */ -const char *history_entry_get_title(const struct history_entry *entry) +const char *browser_window_history_entry_get_title( + const struct history_entry *entry) { return entry->page.title; } diff --git a/desktop/browser_history.h b/desktop/browser_history.h new file mode 100644 index 000000000..f3e524baf --- /dev/null +++ b/desktop/browser_history.h @@ -0,0 +1,141 @@ +/* + * Copyright 2006 James Bursa <bursa@users.sourceforge.net> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Browser history tree (interface). + */ + +#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; + +nserror browser_window_history_create(struct browser_window *bw); +nserror browser_window_history_clone(const struct browser_window *existing, + struct browser_window *clone); +void browser_window_history_add(struct browser_window *bw, + struct hlcache_handle *content, lwc_string *frag_id); +void browser_window_history_update(struct browser_window *bw, + struct hlcache_handle *content); +void browser_window_history_destroy(struct browser_window *bw); +void browser_window_history_back(struct browser_window *bw, bool new_window); +void browser_window_history_forward(struct browser_window *bw, bool new_window); +bool browser_window_history_back_available(struct browser_window *bw); +bool browser_window_history_forward_available(struct browser_window *bw); +void browser_window_history_size(struct browser_window *bw, + int *width, int *height); +bool browser_window_history_redraw(struct browser_window *bw, + const struct redraw_context *ctx); +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); +bool browser_window_history_click(struct browser_window *bw, + int x, int y, bool new_window); +const char *browser_window_history_position_url(struct browser_window *bw, + int x, int y); + +/** + * Callback function type for history enumeration + * + * \param bw The browser window with history being enumerated + * \param x0, y0, x1, y1 Coordinates of entry in history tree view + * \param entry Current history entry + * \return true to continue enumeration, false to cancel enumeration + */ +typedef bool (*browser_window_history_enumerate_cb)( + const struct browser_window *bw, + 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. + * + * \param bw The browser window to enumerate history of + * \param cb callback function + * \param user_data context pointer passed to 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 + * + * \param bw The browser window to enumerate history of + * \param cb The callback function + * \param user_data Data passed to the callback + */ +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 + * + * \param bw The browser window to enumerate history of + * \param cb The callback function + * \param user_data Data passed to the callback + */ +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 + */ +const char *browser_window_history_entry_get_url( + const struct history_entry *entry); + +/** + * Returns the URL to a history entry + * + * \param entry the history entry to retrieve the fragment id from + * \return the fragment id + */ +const char *browser_window_history_entry_get_fragment_id( + const struct history_entry *entry); + +/** + * Returns the title of a history entry + * + * \param entry the history entry to retrieve the title from + * \return the title + */ +const char *browser_window_history_entry_get_title( + const struct history_entry *entry); + +/** + * Navigate to specified history entry, optionally in new window + * + * \param bw browser window + * \param entry entry to open + * \param new_window open entry in new window + */ +void browser_window_history_go(struct browser_window *bw, + struct history_entry *entry, bool new_window); + +#endif diff --git a/desktop/browser_private.h b/desktop/browser_private.h index 4412f4bf4..d2c48d704 100644 --- a/desktop/browser_private.h +++ b/desktop/browser_private.h @@ -25,6 +25,7 @@ #define _NETSURF_DESKTOP_BROWSER_PRIVATE_H_ #include <stdbool.h> +#include <libwapcaplet/libwapcaplet.h> #include "desktop/browser.h" @@ -87,9 +88,6 @@ struct browser_window { /** Refresh interval (-1 if undefined) */ int refresh_interval; - /** Window has been resized, and content needs reformatting. */ - bool reformat_pending; - /** Window dimensions */ int x; int y; @@ -163,4 +161,17 @@ struct browser_window { int status_miss; /**< Number of times status was really updated. */ }; + + +nserror browser_window_initialise_common(enum browser_window_create_flags flags, + struct browser_window *bw, struct browser_window *existing); + +/** + * Update the extent of the inside of a browser window to that of the current + * content + * + * \param bw browser_window to update the extent of + */ +void browser_window_update_extent(struct browser_window *bw); + #endif diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c index 13c6ac93b..c0ca16128 100644 --- a/desktop/cookie_manager.c +++ b/desktop/cookie_manager.c @@ -22,13 +22,15 @@ #include <stdlib.h> +#include <string.h> -#include "content/urldb.h" -#include "desktop/cookie_manager.h" -#include "desktop/treeview.h" #include "utils/messages.h" #include "utils/utils.h" #include "utils/log.h" +#include "content/urldb.h" + +#include "desktop/cookie_manager.h" +#include "desktop/treeview.h" enum cookie_manager_field { COOKIE_M_NAME, @@ -836,7 +838,7 @@ void cookie_manager_redraw(int x, int y, struct rect *clip, /* Exported interface, documented in cookie_manager.h */ -void cookie_manager_mouse_action(browser_mouse_state mouse, int x, int y) +void cookie_manager_mouse_action(enum browser_mouse_state mouse, int x, int y) { treeview_mouse_action(cm_ctx.tree, mouse, x, y); } diff --git a/desktop/cookie_manager.h b/desktop/cookie_manager.h index aa61a3e65..3565caf63 100644 --- a/desktop/cookie_manager.h +++ b/desktop/cookie_manager.h @@ -26,12 +26,12 @@ #include <stdbool.h> #include <stdint.h> -#include "desktop/browser.h" #include "desktop/core_window.h" #include "desktop/textinput.h" #include "utils/errors.h" struct cookie_data; +enum browser_mouse_state; /** * Initialise the cookie manager. @@ -92,7 +92,7 @@ void cookie_manager_redraw(int x, int y, struct rect *clip, * \param x X coordinate * \param y Y coordinate */ -void cookie_manager_mouse_action(browser_mouse_state mouse, int x, int y); +void cookie_manager_mouse_action(enum browser_mouse_state mouse, int x, int y); /** * Key press handling. diff --git a/desktop/download.c b/desktop/download.c index b775eb18e..0f3fcb6f5 100644 --- a/desktop/download.c +++ b/desktop/download.c @@ -23,10 +23,12 @@ #include <assert.h> #include <stdlib.h> +#include <string.h> #include "content/llcache.h" #include "desktop/download.h" -#include "desktop/gui.h" +#include "desktop/gui_factory.h" +#include "utils/corestrings.h" #include "utils/http.h" #include "utils/url.h" #include "utils/utils.h" @@ -69,11 +71,11 @@ static char *download_parse_filename(const char *filename) * \param url URL of item being fetched * \return Default filename, or NULL on memory exhaustion */ -static char *download_default_filename(const char *url) +static char *download_default_filename(nsurl *url) { char *nice; - if (url_nice(url, &nice, false) == URL_FUNC_OK) + if (url_nice(nsurl_access(url), &nice, false) == NSERROR_OK) return nice; return NULL; @@ -113,26 +115,18 @@ static nserror download_context_process_headers(download_context *ctx) http_header = llcache_handle_get_header(ctx->llcache, "Content-Disposition"); if (http_header != NULL) { - lwc_string *filename; lwc_string *filename_value; http_content_disposition *disposition; - if (lwc_intern_string("filename", SLEN("filename"), - &filename) != lwc_error_ok) { - http_content_type_destroy(content_type); - return NSERROR_NOMEM; - } - error = http_parse_content_disposition(http_header, &disposition); if (error != NSERROR_OK) { - lwc_string_unref(filename); http_content_type_destroy(content_type); return error; } error = http_parameter_list_find_item(disposition->parameters, - filename, &filename_value); + corestring_lwc_filename, &filename_value); if (error == NSERROR_OK) { ctx->filename = download_parse_filename( lwc_string_data(filename_value)); @@ -140,15 +134,13 @@ static nserror download_context_process_headers(download_context *ctx) } http_content_disposition_destroy(disposition); - lwc_string_unref(filename); } ctx->mime_type = lwc_string_ref(content_type->media_type); ctx->total_length = length; if (ctx->filename == NULL) { ctx->filename = download_default_filename( - nsurl_access( - llcache_handle_get_url(ctx->llcache))); + llcache_handle_get_url(ctx->llcache)); } http_content_type_destroy(content_type); @@ -160,7 +152,7 @@ static nserror download_context_process_headers(download_context *ctx) } /* Create the frontend window */ - ctx->window = gui_download_window_create(ctx, ctx->parent); + ctx->window = guit->download->create(ctx, ctx->parent); if (ctx->window == NULL) { free(ctx->filename); ctx->filename = NULL; @@ -210,7 +202,7 @@ static nserror download_callback(llcache_handle *handle, if (error == NSERROR_OK) { /** \todo Lose ugly cast */ - error = gui_download_window_data(ctx->window, + error = guit->download->data(ctx->window, (char *) event->data.data.buf, event->data.data.len); if (error != NSERROR_OK) @@ -222,7 +214,7 @@ static nserror download_callback(llcache_handle *handle, case LLCACHE_EVENT_DONE: /* There may be no associated window if there was no data or headers */ if (ctx->window != NULL) - gui_download_window_done(ctx->window); + guit->download->done(ctx->window); else download_context_destroy(ctx); @@ -230,7 +222,7 @@ static nserror download_callback(llcache_handle *handle, case LLCACHE_EVENT_ERROR: if (ctx->window != NULL) - gui_download_window_error(ctx->window, event->data.msg); + guit->download->error(ctx->window, event->data.msg); else download_context_destroy(ctx); @@ -290,9 +282,9 @@ void download_context_abort(download_context *ctx) } /* See download.h for documentation */ -const char *download_context_get_url(const download_context *ctx) +nsurl *download_context_get_url(const download_context *ctx) { - return nsurl_access(llcache_handle_get_url(ctx->llcache)); + return llcache_handle_get_url(ctx->llcache); } /* See download.h for documentation */ diff --git a/desktop/download.h b/desktop/download.h index f53f38b95..dc2befd90 100644 --- a/desktop/download.h +++ b/desktop/download.h @@ -28,6 +28,7 @@ struct gui_window; struct llcache_handle; +struct nsurl; /** Type of a download context */ typedef struct download_context download_context; @@ -67,10 +68,14 @@ void download_context_abort(download_context *ctx); /** * Retrieve the URL for a download * - * \param ctx Context to retrieve URL from - * \return URL string + * The caller is borrowing the url reference from the underlying low + * level cache object. If it is used beyond the immediate scope of the + * caller an additional reference should be made. + * + * \param ctx Context to retrieve URL from + * \return URL object */ -const char *download_context_get_url(const download_context *ctx); +struct nsurl *download_context_get_url(const download_context *ctx); /** * Retrieve the MIME type for a download diff --git a/desktop/frames.c b/desktop/frames.c index 3f7613f32..534cca4f7 100644 --- a/desktop/frames.c +++ b/desktop/frames.c @@ -28,12 +28,11 @@ #include <string.h> #include <time.h> #include <math.h> + #include "utils/config.h" #include "content/hlcache.h" #include "desktop/browser_private.h" #include "desktop/frames.h" -#include "desktop/local_history.h" -#include "desktop/gui.h" #include "desktop/scrollbar.h" #include "desktop/selection.h" #include "utils/log.h" @@ -209,7 +208,8 @@ void browser_window_create_iframes(struct browser_window *bw, window = &(bw->iframes[index++]); /* Initialise common parts */ - browser_window_initialise_common(window, NULL); + browser_window_initialise_common(BW_CREATE_NONE, + window, NULL); /* window characteristics */ window->browser_window_type = BROWSER_WINDOW_IFRAME; @@ -251,7 +251,7 @@ void browser_window_create_iframes(struct browser_window *bw, browser_window_navigate(window, cur->url, hlcache_handle_get_url(bw->current_content), - BROWSER_WINDOW_NONE, + BW_NAVIGATE_UNVERIFIABLE, NULL, NULL, bw->current_content); @@ -314,7 +314,8 @@ void browser_window_create_frameset(struct browser_window *bw, window = &bw->children[index]; /* Initialise common parts */ - browser_window_initialise_common(window, NULL); + browser_window_initialise_common(BW_CREATE_NONE, + window, NULL); /* window characteristics */ if (frame->children) @@ -387,7 +388,8 @@ void browser_window_create_frameset(struct browser_window *bw, browser_window_navigate(window, frame->url, hlcache_handle_get_url(parent), - BROWSER_WINDOW_HISTORY, + BW_NAVIGATE_HISTORY | + BW_NAVIGATE_UNVERIFIABLE, NULL, NULL, parent); diff --git a/desktop/global_history.c b/desktop/global_history.c index e8d99efc2..7d679e5a2 100644 --- a/desktop/global_history.c +++ b/desktop/global_history.c @@ -18,15 +18,18 @@ #include <stdlib.h> +#include <string.h> -#include "content/urldb.h" -#include "desktop/global_history.h" -#include "desktop/treeview.h" #include "utils/messages.h" #include "utils/utils.h" #include "utils/utf8.h" #include "utils/libdom.h" #include "utils/log.h" +#include "content/urldb.h" + +#include "desktop/global_history.h" +#include "desktop/treeview.h" +#include "desktop/browser.h" #define N_DAYS 28 #define N_SEC_PER_DAY (60 * 60 * 24) @@ -676,23 +679,22 @@ static nserror global_history_tree_node_entry_cb( case TREE_MSG_NODE_LAUNCH: { nserror error; - struct browser_window *clone = NULL; - enum browser_window_nav_flags flags = - BROWSER_WINDOW_VERIFIABLE | - BROWSER_WINDOW_HISTORY | - BROWSER_WINDOW_TAB; + struct browser_window *existing = NULL; + enum browser_window_create_flags flags = + BW_CREATE_HISTORY; - /* TODO: Set clone window, to window that new tab appears in */ + /* TODO: Set existing to window that new tab appears in */ if (msg.data.node_launch.mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2) || - clone == NULL) { + existing == NULL) { /* Shift or Ctrl launch, open in new window rather * than tab. */ - flags ^= BROWSER_WINDOW_TAB; + /* TODO: flags ^= BW_CREATE_TAB; */ } - error = browser_window_create(flags, e->url, NULL, clone, NULL); + error = browser_window_create(flags, e->url, NULL, + existing, NULL); if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } @@ -828,21 +830,21 @@ static nserror global_history_export_enter_cb(void *ctx, void *node_data, enum treeview_node_type type, bool *abort) { struct treeview_export_walk_ctx *tw = ctx; + nserror ret; if (type == TREE_NODE_ENTRY) { struct global_history_entry *e = node_data; - utf8_convert_ret ret; char *t_text; char *u_text; ret = utf8_to_html(e->data[GH_TITLE].value, "iso-8859-1", e->data[GH_TITLE].value_len, &t_text); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return NSERROR_SAVE_FAILED; ret = utf8_to_html(e->data[GH_URL].value, "iso-8859-1", e->data[GH_URL].value_len, &u_text); - if (ret != UTF8_CONVERT_OK) { + if (ret != NSERROR_OK) { free(t_text); return NSERROR_SAVE_FAILED; } @@ -855,12 +857,11 @@ static nserror global_history_export_enter_cb(void *ctx, void *node_data, } else if (type == TREE_NODE_FOLDER) { struct global_history_folder *f = node_data; - utf8_convert_ret ret; char *f_text; ret = utf8_to_html(f->data.value, "iso-8859-1", f->data.value_len, &f_text); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return NSERROR_SAVE_FAILED; fprintf(tw->fp, "<li><h4>%s</h4>\n<ul>\n", f_text); @@ -954,10 +955,11 @@ bool global_history_has_selection(void) bool global_history_get_selection(nsurl **url, const char **title) { struct global_history_entry *e; + enum treeview_node_type type; void *v; - treeview_get_selection(gh_ctx.tree, &v); - if (v == NULL) { + type = treeview_get_selection(gh_ctx.tree, &v); + if (type != TREE_NODE_ENTRY || v == NULL) { *url = NULL; *title = NULL; return false; diff --git a/desktop/global_history.h b/desktop/global_history.h index 7c49cfcb7..463ab1b9c 100644 --- a/desktop/global_history.h +++ b/desktop/global_history.h @@ -22,12 +22,12 @@ #include <stdbool.h> #include <stdint.h> -#include "desktop/browser.h" #include "desktop/core_window.h" #include "desktop/textinput.h" #include "utils/errors.h" #include "utils/nsurl.h" +enum browser_mouse_state; /** * Initialise the global history. @@ -92,7 +92,7 @@ void global_history_redraw(int x, int y, struct rect *clip, * \param x X coordinate * \param y Y coordinate */ -void global_history_mouse_action(browser_mouse_state mouse, int x, int y); +void global_history_mouse_action(enum browser_mouse_state mouse, int x, int y); /** * Key press handling. diff --git a/desktop/gui.h b/desktop/gui.h index 9d35e1727..21dd85e68 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -1,6 +1,5 @@ /* - * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> - * Copyright 2004 James Bursa <bursa@users.sourceforge.net> + * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -18,13 +17,20 @@ */ /** \file - * Interface to platform-specific gui functions. + * Interface to platform-specific gui operation tables. */ #ifndef _NETSURF_DESKTOP_GUI_H_ #define _NETSURF_DESKTOP_GUI_H_ -typedef enum { +#include <stddef.h> + +#include "utils/types.h" +#include "utils/errors.h" +#include "desktop/plot_style.h" +#include "desktop/mouse.h" + +typedef enum gui_save_type { GUI_SAVE_SOURCE, GUI_SAVE_DRAW, GUI_SAVE_PDF, @@ -48,133 +54,529 @@ typedef enum { GDRAGGING_OTHER } gui_drag_type; +typedef enum { + GW_CREATE_NONE = 0, /* New window */ + GW_CREATE_CLONE = (1 << 0), /* Clone existing window */ + GW_CREATE_TAB = (1 << 1) /* In same window as existing */ +} gui_window_create_flags; + struct gui_window; struct gui_download_window; struct browser_window; struct form_control; +struct ssl_cert_info; +struct hlcache_handle; +struct download_context; +struct nsurl; +struct gui_file_table; +struct gui_llcache_table; +struct gui_search_web_table; -#include <stdbool.h> +typedef struct nsnsclipboard_styles { + size_t start; /**< Start of run */ -#include <libwapcaplet/libwapcaplet.h> -#include <libcss/libcss.h> + plot_font_style_t style; /**< Style to give text run */ +} nsclipboard_styles; -#include "utils/config.h" -#include "content/hlcache.h" -#include "desktop/download.h" -#include "desktop/mouse.h" -#include "desktop/search.h" -#include "utils/errors.h" +/** + * Graphical user interface window function table. + * + * function table implementing window operations + */ +struct gui_window_table { + + /* Mandantory entries */ + + /** + * Create and open a gui window for a browsing context. + * + * \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 + * + * If GW_CREATE_CLONE flag is set existing is non-NULL. + * + * Front end's gui_window must include a reference to the + * browser window passed in the bw param. + */ + struct gui_window *(*create)(struct browser_window *bw, + struct gui_window *existing, + gui_window_create_flags flags); + + /** + * Destroy previously created gui window + */ + void (*destroy)(struct gui_window *g); + + /** + * Force a redraw of the entire contents of a window. + * + * @todo this API should be merged with update. + * + * \param g gui_window to redraw + */ + void (*redraw)(struct gui_window *g); + + /** + * Redraw an area of a window. + * + * \param g gui_window + * \param rect area to redraw + */ + void (*update)(struct gui_window *g, const struct rect *rect); + + /** + * 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 + */ + bool (*get_scroll)(struct gui_window *g, int *sx, int *sy); -void gui_poll(bool active); -void gui_quit(void); - -struct gui_window *gui_create_browser_window(struct browser_window *bw, - struct browser_window *clone, bool new_tab); -void gui_window_destroy(struct gui_window *g); -void gui_window_set_title(struct gui_window *g, const char *title); -void gui_window_redraw_window(struct gui_window *g); -void gui_window_update_box(struct gui_window *g, - const struct rect *rect); -bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy); -void gui_window_set_scroll(struct gui_window *g, int sx, int sy); -void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, - int x1, int y1); -void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, - bool scaled); -void gui_window_update_extent(struct gui_window *g); -void gui_window_set_status(struct gui_window *g, const char *text); -void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape); -void gui_window_hide_pointer(struct gui_window *g); -void gui_window_set_url(struct gui_window *g, const char *url); -void gui_window_start_throbber(struct gui_window *g); -void gui_window_stop_throbber(struct gui_window *g); -void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon); -void gui_window_set_search_ico(hlcache_handle *ico); -void gui_window_place_caret(struct gui_window *g, int x, int y, int height, - const struct rect *clip); -void gui_window_remove_caret(struct gui_window *g); -void gui_window_new_content(struct gui_window *g); -bool gui_window_scroll_start(struct gui_window *g); - -bool gui_window_drag_start(struct gui_window *g, gui_drag_type type, - const struct rect *rect); - -void gui_window_save_link(struct gui_window *g, const char *url, - const char *title); - -struct gui_download_window *gui_download_window_create(download_context *ctx, - struct gui_window *parent); -nserror gui_download_window_data(struct gui_download_window *dw, - const char *data, unsigned int size); -void gui_download_window_error(struct gui_download_window *dw, - const char *error_msg); -void gui_download_window_done(struct gui_download_window *dw); - -void gui_drag_save_object(gui_save_type type, hlcache_handle *c, - struct gui_window *g); -void gui_drag_save_selection(struct gui_window *g, const char *selection); -void gui_start_selection(struct gui_window *g); -void gui_clear_selection(struct gui_window *g); + /** + * Set the scroll position of a browser window. + * + * \param g gui_window to scroll + * \param sx point to place at top-left of window + * \param sy point to place at top-left of window + */ + void (*set_scroll)(struct gui_window *g, int sx, int sy); + /** + * Find the current dimensions of a browser window's content area. + * + * @todo The implementations of this are buggy and its only + * used from frames code. + * + * \param g gui_window to measure + * \param width receives width of window + * \param height receives height of window + * \param scaled whether to return scaled values + */ + void (*get_dimensions)(struct gui_window *g, int *width, int *height, bool scaled); + + /** + * Update the extent of the inside of a browser window to that of the + * current content. + * + * @todo this is used to update scroll bars does it need + * renaming? some frontends (windows) do not even implement it. + * + * \param g gui_window to update the extent of + */ + void (*update_extent)(struct gui_window *g); + + /** + * Reformat a window. + * + * This is used to perform reformats when the page contents + * require reformating. The reformat is requested using + * browser_window_schedule_reformat and occours via a scheduled + * callback hence from top level context. + * + * \param g gui_window to reformat. + */ + void (*reformat)(struct gui_window *g); + + + /* Optional entries */ + + /** + * Set the title of a window. + * + * \param g window to update + * \param title new window title + */ + void (*set_title)(struct gui_window *g, const char *title); + + /** + * set the navigation url. + */ + void (*set_url)(struct gui_window *g, const char *url); + + /** set favicon */ + void (*set_icon)(struct gui_window *g, struct hlcache_handle *icon); + + /** + * Set the status bar of a browser window. + * + * \param g gui_window to update + * \param text new status text + */ + void (*set_status)(struct gui_window *g, const char *text); + + /** + * Change mouse pointer shape + */ + void (*set_pointer)(struct gui_window *g, gui_pointer_shape shape); + + /** + * 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 + */ + void (*place_caret)(struct gui_window *g, int x, int y, int height, const struct rect *clip); + + /** + * Remove the caret, if present. + * + * \param g window with caret + */ + void (*remove_caret)(struct gui_window *g); + + /** start the navigation throbber. */ + void (*start_throbber)(struct gui_window *g); + + /** stop the navigation throbber. */ + void (*stop_throbber)(struct gui_window *g); + + /** start a drag operation within a window */ + bool (*drag_start)(struct gui_window *g, gui_drag_type type, const struct rect *rect); + + /** save link operation */ + void (*save_link)(struct gui_window *g, const char *url, const char *title); + + /** + * Scrolls the specified area of a browser window into view. + * + * @todo investigate if this can be merged with set_scroll + * which is what the default implementation used by most + * toolkits uses. + * + * \param g gui_window to scroll + * \param x0 left point to ensure visible + * \param y0 bottom point to ensure visible + * \param x1 right point to ensure visible + * \param y1 top point to ensure visible + */ + void (*scroll_visible)(struct gui_window *g, int x0, int y0, int x1, int y1); + + /** + * Starts drag scrolling of a browser window + * + * \param g the window to scroll + */ + bool (*scroll_start)(struct gui_window *g); + + /** + * Called when the gui_window has new content. + * + * \param g the gui_window that has new content + */ + void (*new_content)(struct gui_window *g); + + /** + * Called when file chooser gadget is activated + */ + void (*file_gadget_open)(struct gui_window *g, struct hlcache_handle *hl, struct form_control *gadget); + + /** object dragged to window*/ + void (*drag_save_object)(struct gui_window *g, struct hlcache_handle *c, gui_save_type type); + + /** drag selection save */ + void (*drag_save_selection)(struct gui_window *g, const char *selection); + + /** selection started */ + void (*start_selection)(struct gui_window *g); +}; /** - * Core asks front end for clipboard contents. - * - * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core - * \param length Byte length of UTF-8 text in buffer + * function table for download windows. */ -void gui_get_clipboard(char **buffer, size_t *length); +struct gui_download_table { + struct gui_download_window *(*create)(struct download_context *ctx, struct gui_window *parent); + + nserror (*data)(struct gui_download_window *dw, const char *data, unsigned int size); + + void (*error)(struct gui_download_window *dw, const char *error_msg); + + void (*done)(struct gui_download_window *dw); +}; -typedef struct nsnsclipboard_styles { - size_t start; /**< Start of run */ - plot_font_style_t style; /**< Style to give text run */ -} nsclipboard_styles; /** - * Core tells front end to put given text in clipboard - * - * \param buffer UTF-8 text, owned by core - * \param length Byte length of UTF-8 text in buffer - * \param styles Array of styles given to text runs, owned by core, or NULL - * \param n_styles Number of text run styles in array + * function table for clipboard operations. */ -void gui_set_clipboard(const char *buffer, size_t length, - nsclipboard_styles styles[], int n_styles); +struct gui_clipboard_table { + /** + * Core asks front end for clipboard contents. + * + * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core + * \param length Byte length of UTF-8 text in buffer + */ + void (*get)(char **buffer, size_t *length); + + /** + * Core tells front end to put given text in clipboard + * + * \param buffer UTF-8 text, owned by core + * \param length Byte length of UTF-8 text in buffer + * \param styles Array of styles given to text runs, owned by core, or NULL + * \param n_styles Number of text run styles in array + */ + void (*set)(const char *buffer, size_t length, nsclipboard_styles styles[], int n_styles); +}; +/** + * function table for fetcher operations + */ +struct gui_fetch_table { + /* Mandantory entries */ -void gui_create_form_select_menu(struct browser_window *bw, - struct form_control *control); + /** + * Determine the MIME type of a local file. + * + * @note used in file fetcher + * + * \param unix_path Unix style path to file on disk + * \return Pointer to MIME type string (should not be freed) - + * invalidated on next call to fetch_filetype. + */ + const char *(*filetype)(const char *unix_path); -void gui_launch_url(const char *url); + /* Optional entries */ -struct ssl_cert_info; + /** + * Callback to translate resource to full url. + * + * @note used in resource fetcher + * + * Transforms a resource: path into a full URL. The returned URL + * is used as the target for a redirect. The caller takes ownership of + * the returned nsurl including unrefing it when finished with it. + * + * \param path The path of the resource to locate. + * \return A string containing the full URL of the target object or + * NULL if no suitable resource can be found. + */ + struct nsurl* (*get_resource_url)(const char *path); -void gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs, - unsigned long num, nserror (*cb)(bool proceed, void *pw), - void *cbpw); + /** + * Find a MIME type for a local file + * + * @note only used in curl fetcher on RISC OS otherwise its a + * strdup of filetype. + * + * \param ro_path RISC OS style path to file on disk + * \return MIME type string (on heap, caller should free), or NULL + */ + char *(*mimetype)(const char *ro_path); + +}; + + +/** + * User interface utf8 characterset conversion routines. + */ +struct gui_utf8_table { + /** + * Convert a UTF-8 encoded string into the system local encoding + * + * \param string The string to convert + * \param len The length (in bytes) of the string, or 0 + * \param result Pointer to location in which to store result + * \return An nserror code + */ + nserror (*utf8_to_local)(const char *string, size_t len, char **result); + + /** + * Convert a string encoded in the system local encoding to UTF-8 + * + * \param string The string to convert + * \param len The length (in bytes) of the string, or 0 + * \param result Pointer to location in which to store result + * \return An nserror code + */ + nserror (*local_to_utf8)(const char *string, size_t len, char **result); +}; /** - * Callback to translate resource to full url. + * function table for page text search. + */ +struct gui_search_table { + /** + * Change the displayed search status. + * + * \param found search pattern matched in text + * \param p gui private data pointer provided with search callbacks + */ + void (*status)(bool found, void *p); + + /** + * display hourglass while searching. + * + * \param active start/stop indicator + * \param p gui private data pointer provided with search callbacks + */ + void (*hourglass)(bool active, void *p); + + /** + * add search string to recent searches list + * front has full liberty how to implement the bare notification; + * core gives no guarantee of the integrity of the string + * + * \param string search pattern + * \param p gui private data pointer provided with search callbacks + */ + void (*add_recent)(const char *string, void *p); + + /** + * activate search forwards button in gui + * + * \param active activate/inactivate + * \param p gui private data pointer provided with search callbacks + */ + void (*forward_state)(bool active, void *p); + + /** + * activate search back button in gui + * + * \param active activate/inactivate + * \param p gui private data pointer provided with search callbacks + */ + void (*back_state)(bool active, void *p); +}; + +/** + * Graphical user interface browser misc function table. * - * Transforms a resource: path into a full URL. The returned URL - * is used as the target for a redirect. The caller takes ownership of - * the returned nsurl including unrefing it when finished with it. + * function table implementing GUI interface to miscelaneous browser + * functionality + */ +struct gui_browser_table { + /* Mandantory entries */ + + /** + * called to let the frontend update its state and run any + * I/O operations. + */ + void (*poll)(bool active); + + /** + * Schedule a callback. + * + * \param t interval before the callback should be made in ms or + * negative value to remove any existing callback. + * \param callback callback function + * \param p user parameter passed to callback function + * \return NSERROR_OK on sucess or appropriate error on faliure + * + * The callback function will be called as soon as possible + * after the timeout has elapsed. + * + * Additional calls with the same callback and user parameter will + * reset the callback time to the newly specified value. + * + */ + nserror (*schedule)(int t, void (*callback)(void *p), void *p); + + /* Optional entries */ + + /** called to allow the gui to cleanup */ + void (*quit)(void); + + /** + * core has no fetcher for url + */ + nserror (*launch_url)(struct nsurl *url); + + /** + * create a form select menu + */ + void (*create_form_select_menu)(struct browser_window *bw, struct form_control *control); + + /** + * verify certificate + */ + void (*cert_verify)(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw); + + /** + * Prompt user for login + */ + void (*login)(struct nsurl *url, const char *realm, + nserror (*cb)(bool proceed, void *pw), void *cbpw); + +}; + +/** + * NetSurf operation function table * - * \param path The path of the resource to locate. - * \return A string containing the full URL of the target object or - * NULL if no suitable resource can be found. + * Function table implementing interface operations for the browser core. */ -nsurl* gui_get_resource_url(const char *path); +struct netsurf_table { + + /** + * Browser table. + * + * Provides miscellaneous browser functionality. The table + * is mandantory and must be provided. + */ + struct gui_browser_table *browser; + + /** Window table */ + struct gui_window_table *window; + + /** Download table */ + struct gui_download_table *download; + + /** Clipboard table */ + struct gui_clipboard_table *clipboard; + + /** Fetcher table */ + struct gui_fetch_table *fetch; + + /** + * File table + * + * Provides file and filename operations to the core. The + * table is optional and may be NULL in which case the default + * posix compliant operations will be used. + */ + struct gui_file_table *file; + + /** + * UTF8 table. + * + * Provides for conversion between the gui local character + * encoding and utf8. The table optional and may be NULL which + * implies the local encoding is utf8. + */ + struct gui_utf8_table *utf8; + + /** + * Page search table. + * + * Provides routines for the interactive text search on a page. + */ + struct gui_search_table *search; -/** css callback to obtain named system colours from a frontend. */ -css_error gui_system_colour(void *pw, lwc_string *name, css_color *color); + /** + * Web search table. + * + * Used by the web search provider system. The table is + * optional and may be NULL which uses the default empty + * implementation. + */ + struct gui_search_web_table *search_web; -/** Obtain a named system colour from a frontend. */ -colour gui_system_colour_char(const char *name); + /** + * Low level cache table. + * + * Used by the low level cache to push objects to persistant + * storage. The table is optional and may be NULL which + * uses the default implementation. + */ + struct gui_llcache_table *llcache; +}; -bool gui_system_colour_init(void); -void gui_system_colour_finalize(void); #endif diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c new file mode 100644 index 000000000..977805e9c --- /dev/null +++ b/desktop/gui_factory.c @@ -0,0 +1,705 @@ +/* + * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "content/hlcache.h" +#include "content/backing_store.h" + +#include "desktop/download.h" +#include "desktop/searchweb.h" +#include "desktop/gui_factory.h" +#include "utils/file.h" + +/** The global interface table */ +struct netsurf_table *guit = NULL; + + +static void gui_default_window_set_title(struct gui_window *g, const char *title) +{ +} + +static void gui_default_window_set_url(struct gui_window *g, const char *url) +{ +} + +static void gui_default_window_start_throbber(struct gui_window *g) +{ +} + +static void gui_default_window_stop_throbber(struct gui_window *g) +{ +} + +static bool gui_default_window_drag_start(struct gui_window *g, + gui_drag_type type, + const struct rect *rect) +{ + return true; +} + +static void gui_default_window_save_link(struct gui_window *g, + const char *url, + const char *title) +{ +} + +static void gui_default_window_set_icon(struct gui_window *g, + hlcache_handle *icon) +{ +} + +static void gui_default_window_scroll_visible(struct gui_window *g, + int x0, int y0, + int x1, int y1) +{ + guit->window->set_scroll(g, x0, y0); +} + +static void gui_default_window_new_content(struct gui_window *g) +{ +} + + +static bool gui_default_window_scroll_start(struct gui_window *g) +{ + return true; +} + +static void gui_default_window_set_pointer(struct gui_window *g, + gui_pointer_shape shape) +{ +} + +static void gui_default_window_set_status(struct gui_window *g, + const char *text) +{ +} + +static void gui_default_window_place_caret(struct gui_window *g, + int x, int y, int height, + const struct rect *clip) +{ +} + +static void gui_default_window_remove_caret(struct gui_window *g) +{ +} + +static void gui_default_window_file_gadget_open(struct gui_window *g, + hlcache_handle *hl, + struct form_control *gadget) +{ +} + +static void gui_default_window_drag_save_object(struct gui_window *g, + hlcache_handle *c, + gui_save_type type) +{ +} + +static void gui_default_window_drag_save_selection(struct gui_window *g, + const char *selection) +{ +} + +static void gui_default_window_start_selection(struct gui_window *g) +{ +} + + +/** verify window table is valid */ +static nserror verify_window_register(struct gui_window_table *gwt) +{ + /* check table is present */ + if (gwt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* check the mandantory fields are set */ + if (gwt->create == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->destroy == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->redraw == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->update == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->get_scroll == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->set_scroll == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->get_dimensions == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->update_extent == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gwt->reformat == NULL) { + return NSERROR_BAD_PARAMETER; + } + + + /* fill in the optional entries with defaults */ + if (gwt->set_title == NULL) { + gwt->set_title = gui_default_window_set_title; + } + if (gwt->set_url == NULL) { + gwt->set_url = gui_default_window_set_url; + } + if (gwt->set_icon == NULL) { + gwt->set_icon = gui_default_window_set_icon; + } + if (gwt->set_status == NULL) { + gwt->set_status = gui_default_window_set_status; + } + if (gwt->set_pointer == NULL) { + gwt->set_pointer = gui_default_window_set_pointer; + } + if (gwt->place_caret == NULL) { + gwt->place_caret = gui_default_window_place_caret; + } + if (gwt->remove_caret == NULL) { + gwt->remove_caret = gui_default_window_remove_caret; + } + if (gwt->start_throbber == NULL) { + gwt->start_throbber = gui_default_window_start_throbber; + } + if (gwt->stop_throbber == NULL) { + gwt->stop_throbber = gui_default_window_stop_throbber; + } + if (gwt->drag_start == NULL) { + gwt->drag_start = gui_default_window_drag_start; + } + if (gwt->save_link == NULL) { + gwt->save_link = gui_default_window_save_link; + } + if (gwt->scroll_visible == NULL) { + gwt->scroll_visible = gui_default_window_scroll_visible; + } + if (gwt->new_content == NULL) { + gwt->new_content = gui_default_window_new_content; + } + if (gwt->scroll_start == NULL) { + gwt->scroll_start = gui_default_window_scroll_start; + } + if (gwt->file_gadget_open == NULL) { + gwt->file_gadget_open = gui_default_window_file_gadget_open; + } + if (gwt->drag_save_object == NULL) { + gwt->drag_save_object = gui_default_window_drag_save_object; + } + if (gwt->drag_save_selection == NULL) { + gwt->drag_save_selection = gui_default_window_drag_save_selection; + } + if (gwt->start_selection == NULL) { + gwt->start_selection = gui_default_window_start_selection; + } + + return NSERROR_OK; +} + + + +static struct gui_download_window * +gui_default_download_create(download_context *ctx, struct gui_window *parent) +{ + return NULL; +} + +static nserror gui_default_download_data(struct gui_download_window *dw, + const char *data, unsigned int size) +{ + return NSERROR_OK; +} + +static void gui_default_download_error(struct gui_download_window *dw, + const char *error_msg) +{ +} + +static void gui_default_download_done(struct gui_download_window *dw) +{ +} + + +/** verify download window table is valid */ +static nserror verify_download_register(struct gui_download_table *gdt) +{ + /* check table is present */ + if (gdt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* all enties are mandantory */ + if (gdt->create == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gdt->data == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gdt->error == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gdt->done == NULL) { + return NSERROR_BAD_PARAMETER; + } + + return NSERROR_OK; +} + +static void gui_default_get_clipboard(char **buffer, size_t *length) +{ + *buffer = NULL; + *length = 0; +} + +static void gui_default_set_clipboard(const char *buffer, size_t length, + nsclipboard_styles styles[], int n_styles) +{ +} + +static struct gui_clipboard_table default_clipboard_table = { + .get = gui_default_get_clipboard, + .set = gui_default_set_clipboard, +}; + +/** verify clipboard table is valid */ +static nserror verify_clipboard_register(struct gui_clipboard_table *gct) +{ + /* check table is present */ + if (gct == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* optional operations */ + if (gct->get == NULL) { + gct->get = gui_default_get_clipboard; + } + if (gct->set == NULL) { + gct->set = gui_default_set_clipboard; + } + return NSERROR_OK; +} + +/** + * The default utf8 conversion implementation. + * + * The default implementation assumes the local encoding is utf8 + * allowing the conversion to be a simple copy. + * + * @param [in] string The source string. + * @param [in] len The \a string length or 0 to compute it. + * @param [out] result A pointer to the converted string. + * @result NSERROR_OK or NSERROR_NOMEM if memory could not be allocated. + */ +static nserror gui_default_utf8(const char *string, size_t len, char **result) +{ + assert(string && result); + + if (len == 0) + len = strlen(string); + + *result = strndup(string, len); + if (!(*result)) + return NSERROR_NOMEM; + + return NSERROR_OK; +} + +static struct gui_utf8_table default_utf8_table = { + .utf8_to_local = gui_default_utf8, + .local_to_utf8 = gui_default_utf8, +}; + +/** verify clipboard table is valid */ +static nserror verify_utf8_register(struct gui_utf8_table *gut) +{ + /* check table is present */ + if (gut == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* mandantory operations */ + if (gut->utf8_to_local == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gut->local_to_utf8 == NULL) { + return NSERROR_BAD_PARAMETER; + } + return NSERROR_OK; +} + +static void gui_default_status(bool found, void *p) +{ +} + +static void gui_default_hourglass(bool active, void *p) +{ +} + +static void gui_default_add_recent(const char *string, void *p) +{ +} + +static void gui_default_forward_state(bool active, void *p) +{ +} + +static void gui_default_back_state(bool active, void *p) +{ +} + +static struct gui_search_table default_search_table = { + .status = gui_default_status, + .hourglass = gui_default_hourglass, + .add_recent = gui_default_add_recent, + .forward_state = gui_default_forward_state, + .back_state = gui_default_back_state, +}; + +/** verify search table is valid */ +static nserror verify_search_register(struct gui_search_table *gst) +{ + /* check table is present */ + if (gst == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* fill in the optional entries with defaults */ + if (gst->status == NULL) { + gst->status = default_search_table.status; + } + if (gst->hourglass == NULL) { + gst->hourglass = default_search_table.hourglass; + } + if (gst->add_recent == NULL) { + gst->add_recent = default_search_table.add_recent; + } + if (gst->forward_state == NULL) { + gst->forward_state = default_search_table.forward_state; + } + if (gst->back_state == NULL) { + gst->back_state = default_search_table.back_state; + } + + return NSERROR_OK; +} + +static nserror +gui_default_provider_update(const char *provider_name, + struct bitmap *provider_bitmap) +{ + return NSERROR_OK; +} + +static struct gui_search_web_table default_search_web_table = { + .provider_update = gui_default_provider_update, +}; + +/** verify search table is valid */ +static nserror verify_search_web_register(struct gui_search_web_table *gswt) +{ + /* check table is present */ + if (gswt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* mandantory operations */ + if (gswt->provider_update == NULL) { + return NSERROR_BAD_PARAMETER; + } + + return NSERROR_OK; +} + +/** verify low level cache persistant backing store table is valid */ +static nserror verify_llcache_register(struct gui_llcache_table *glt) +{ + /* check table is present */ + if (glt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* mandantory operations */ + if (glt->store == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (glt->fetch == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (glt->invalidate == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (glt->initialise == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (glt->finalise == NULL) { + return NSERROR_BAD_PARAMETER; + } + + return NSERROR_OK; +} + +static nsurl *gui_default_get_resource_url(const char *path) +{ + return NULL; +} + +static char *gui_default_mimetype(const char *path) +{ + return strdup(guit->fetch->filetype(path)); +} + +/** verify fetch table is valid */ +static nserror verify_fetch_register(struct gui_fetch_table *gft) +{ + /* check table is present */ + if (gft == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* check the mandantory fields are set */ + if (gft->filetype == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* fill in the optional entries with defaults */ + if (gft->get_resource_url == NULL) { + gft->get_resource_url = gui_default_get_resource_url; + } + if (gft->mimetype == NULL) { + gft->mimetype = gui_default_mimetype; + } + + return NSERROR_OK; +} + +/** verify file table is valid */ +static nserror verify_file_register(struct gui_file_table *gft) +{ + /* check table is present */ + if (gft == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* check the mandantory fields are set */ + if (gft->mkpath == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->basename == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->nsurl_to_path == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->path_to_nsurl == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->mkdir_all == NULL) { + return NSERROR_BAD_PARAMETER; + } + + return NSERROR_OK; +} + +static void gui_default_quit(void) +{ +} + + +static nserror gui_default_launch_url(struct nsurl *url) +{ + return NSERROR_NO_FETCH_HANDLER; +} + +static void gui_default_create_form_select_menu(struct browser_window *bw, + struct form_control *control) +{ +} + + +static void gui_default_cert_verify(nsurl *url, + const struct ssl_cert_info *certs, + unsigned long num, + nserror (*cb)(bool proceed, void *pw), + void *cbpw) +{ + cb(false, cbpw); +} + +static void gui_default_401login_open(nsurl *url, const char *realm, + nserror (*cb)(bool proceed, void *pw), void *cbpw) +{ + cb(false, cbpw); +} + +static struct gui_download_table default_download_table = { + .create = gui_default_download_create, + .data = gui_default_download_data, + .error = gui_default_download_error, + .done = gui_default_download_done, +}; + +/** verify browser table is valid */ +static nserror verify_browser_register(struct gui_browser_table *gbt) +{ + /* check table is present */ + if (gbt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* check the mandantory fields are set */ + if (gbt->poll == NULL) { + return NSERROR_BAD_PARAMETER; + } + + if (gbt->schedule == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* fill in the optional entries with defaults */ + if (gbt->quit == NULL) { + gbt->quit = gui_default_quit; + } + if (gbt->launch_url == NULL) { + gbt->launch_url = gui_default_launch_url; + } + if (gbt->create_form_select_menu == NULL) { + gbt->create_form_select_menu = gui_default_create_form_select_menu; + } + if (gbt->cert_verify == NULL) { + gbt->cert_verify = gui_default_cert_verify; + } + if (gbt->login == NULL) { + gbt->login = gui_default_401login_open; + } + return NSERROR_OK; +} + + +/* exported interface documented in desktop/gui_factory.h */ +nserror gui_factory_register(struct netsurf_table *gt) +{ + nserror err; + + /* ensure not already initialised */ + if (guit != NULL) { + return NSERROR_INIT_FAILED; + } + + /* check table is present */ + if (gt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* browser table */ + err = verify_browser_register(gt->browser); + if (err != NSERROR_OK) { + return err; + } + + /* window table */ + err = verify_window_register(gt->window); + if (err != NSERROR_OK) { + return err; + } + + /* fetch table */ + err = verify_fetch_register(gt->fetch); + if (err != NSERROR_OK) { + return err; + } + + /* file table */ + if (gt->file == NULL) { + gt->file = default_file_table; + } + err = verify_file_register(gt->file); + if (err != NSERROR_OK) { + return err; + } + + /* download table */ + if (gt->download == NULL) { + /* set default download table */ + gt->download = &default_download_table; + } + err = verify_download_register(gt->download); + if (err != NSERROR_OK) { + return err; + } + + /* clipboard table */ + if (gt->clipboard == NULL) { + /* set default clipboard table */ + gt->clipboard = &default_clipboard_table; + } + err = verify_clipboard_register(gt->clipboard); + if (err != NSERROR_OK) { + return err; + } + + /* utf8 table */ + if (gt->utf8 == NULL) { + /* set default utf8 table */ + gt->utf8 = &default_utf8_table; + } + err = verify_utf8_register(gt->utf8); + if (err != NSERROR_OK) { + return err; + } + + /* search table */ + if (gt->search == NULL) { + /* set default search table */ + gt->search = &default_search_table; + } + err = verify_search_register(gt->search); + if (err != NSERROR_OK) { + return err; + } + + /* web search table */ + if (gt->search_web == NULL) { + /* set default search table */ + gt->search_web = &default_search_web_table; + } + err = verify_search_web_register(gt->search_web); + if (err != NSERROR_OK) { + return err; + } + + /* llcache table */ + if (gt->llcache == NULL) { + /* set default backing store table */ + gt->llcache = null_llcache_table; + } + err = verify_llcache_register(gt->llcache); + if (err != NSERROR_OK) { + return err; + } + + guit = gt; + + return NSERROR_OK; +} diff --git a/desktop/gui_factory.h b/desktop/gui_factory.h new file mode 100644 index 000000000..3c8661577 --- /dev/null +++ b/desktop/gui_factory.h @@ -0,0 +1,39 @@ +/* + * Copyright 2014 vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Interface to gui interface factory + */ + +#ifndef _NETSURF_DESKTOP_GUI_FACTORY_H_ +#define _NETSURF_DESKTOP_GUI_FACTORY_H_ + +#include "desktop/gui.h" + +/** The global operation table */ +extern struct netsurf_table *guit; + +/** register and verify global operation table + * + * @param gt The global table to register + * @return NSERROR_OK on success or error code on faliure. On faliure + * global table will not be initialised + */ +nserror gui_factory_register(struct netsurf_table *gt); + +#endif diff --git a/desktop/hotlist.c b/desktop/hotlist.c index 01fabc257..f0eda841b 100644 --- a/desktop/hotlist.c +++ b/desktop/hotlist.c @@ -19,6 +19,7 @@ #include <assert.h> #include <stdlib.h> +#include <string.h> #include <dom/dom.h> #include <dom/bindings/hubbub/parser.h> @@ -26,6 +27,7 @@ #include "content/urldb.h" #include "desktop/hotlist.h" #include "desktop/treeview.h" +#include "desktop/browser.h" #include "utils/corestrings.h" #include "utils/messages.h" #include "utils/utils.h" @@ -472,23 +474,22 @@ static nserror hotlist_tree_node_entry_cb( case TREE_MSG_NODE_LAUNCH: { nserror error; - struct browser_window *clone = NULL; - enum browser_window_nav_flags flags = - BROWSER_WINDOW_VERIFIABLE | - BROWSER_WINDOW_HISTORY | - BROWSER_WINDOW_TAB; + struct browser_window *existing = NULL; + enum browser_window_create_flags flags = + BW_CREATE_HISTORY; - /* TODO: Set clone window, to window that new tab appears in */ + /* TODO: Set existing to window that new tab appears in */ if (msg.data.node_launch.mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2) || - clone == NULL) { + existing == NULL) { /* Shift or Ctrl launch, open in new window rather * than tab. */ - flags ^= BROWSER_WINDOW_TAB; + /* TODO: flags ^= BW_CREATE_TAB; */ } - error = browser_window_create(flags, e->url, NULL, clone, NULL); + error = browser_window_create(flags, e->url, NULL, + existing, NULL); if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } @@ -879,21 +880,21 @@ static nserror hotlist_export_enter_cb(void *ctx, void *node_data, enum treeview_node_type type, bool *abort) { struct treeview_export_walk_ctx *tw = ctx; + nserror ret; if (type == TREE_NODE_ENTRY) { struct hotlist_entry *e = node_data; - utf8_convert_ret ret; char *t_text; char *u_text; ret = utf8_to_html(e->data[HL_TITLE].value, "iso-8859-1", e->data[HL_TITLE].value_len, &t_text); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return NSERROR_SAVE_FAILED; ret = utf8_to_html(e->data[HL_URL].value, "iso-8859-1", e->data[HL_URL].value_len, &u_text); - if (ret != UTF8_CONVERT_OK) { + if (ret != NSERROR_OK) { free(t_text); return NSERROR_SAVE_FAILED; } @@ -906,12 +907,11 @@ static nserror hotlist_export_enter_cb(void *ctx, void *node_data, } else if (type == TREE_NODE_FOLDER) { struct hotlist_folder *f = node_data; - utf8_convert_ret ret; char *f_text; ret = utf8_to_html(f->data.value, "iso-8859-1", f->data.value_len, &f_text); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return NSERROR_SAVE_FAILED; if (f == hl_ctx.default_folder) { @@ -1502,10 +1502,11 @@ bool hotlist_has_selection(void) bool hotlist_get_selection(nsurl **url, const char **title) { struct hotlist_entry *e; + enum treeview_node_type type; void *v; - treeview_get_selection(hl_ctx.tree, &v); - if (v == NULL) { + type = treeview_get_selection(hl_ctx.tree, &v); + if (type != TREE_NODE_ENTRY || v == NULL) { *url = NULL; *title = NULL; return false; diff --git a/desktop/hotlist.h b/desktop/hotlist.h index e5ae83499..7e2aa6955 100644 --- a/desktop/hotlist.h +++ b/desktop/hotlist.h @@ -22,12 +22,12 @@ #include <stdbool.h> #include <stdint.h> -#include "desktop/browser.h" #include "desktop/core_window.h" #include "desktop/textinput.h" #include "utils/errors.h" #include "utils/nsurl.h" +enum browser_mouse_state; /** * Initialise the hotlist. @@ -183,7 +183,7 @@ void hotlist_redraw(int x, int y, struct rect *clip, * \param x X coordinate * \param y Y coordinate */ -void hotlist_mouse_action(browser_mouse_state mouse, int x, int y); +void hotlist_mouse_action(enum browser_mouse_state mouse, int x, int y); /** * Key press handling. diff --git a/desktop/knockout.c b/desktop/knockout.c index 0385ee80b..fa827cb39 100644 --- a/desktop/knockout.c +++ b/desktop/knockout.c @@ -64,10 +64,13 @@ #include <assert.h> #include <string.h> -#include "desktop/knockout.h" -#include "desktop/plotters.h" +#include <stdio.h> + #include "image/bitmap.h" #include "utils/log.h" +#include "content/content.h" +#include "desktop/knockout.h" +#include "desktop/plotters.h" /* Define to enable knockout debug */ #undef KNOCKOUT_DEBUG diff --git a/desktop/local_history.h b/desktop/local_history.h deleted file mode 100644 index c4faa8532..000000000 --- a/desktop/local_history.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2006 James Bursa <bursa@users.sourceforge.net> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** \file - * Browser history tree (interface). - */ - -#ifndef _NETSURF_DESKTOP_HISTORY_H_ -#define _NETSURF_DESKTOP_HISTORY_H_ - -#include <stdbool.h> -#include <libwapcaplet/libwapcaplet.h> - -struct hlcache_handle; -struct history; -struct browser_window; -struct history_entry; -struct redraw_context; - -struct history *history_create(void); -struct history *history_clone(struct history *history); -void history_add(struct history *history, struct hlcache_handle *content, - lwc_string *frag_id); -void history_update(struct history *history, struct hlcache_handle *content); -void history_destroy(struct history *history); -void history_back(struct browser_window *bw, struct history *history); -void history_forward(struct browser_window *bw, struct history *history); -bool history_back_available(struct history *history); -bool history_forward_available(struct history *history); -void history_size(struct history *history, int *width, int *height); -bool history_redraw(struct history *history, const struct redraw_context *ctx); -bool history_redraw_rectangle(struct history *history, - int x0, int y0, int x1, int y1, int x, int y, - const struct redraw_context *ctx); -bool history_click(struct browser_window *bw, struct history *history, - int x, int y, bool new_window); -const char *history_position_url(struct history *history, int x, int y); - -/** - * Callback function type for history enumeration - * - * \param history history being enumerated - * \param x0, y0, x1, y1 Coordinates of entry in history tree view - * \param entry Current history entry - * \return true to continue enumeration, false to cancel enumeration - */ -typedef bool (*history_enumerate_cb)(const struct history *history, 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. - * - * \param history history to enumerate - * \param cb callback function - * \param user_data context pointer passed to cb - */ -void history_enumerate(const struct history *history, history_enumerate_cb cb, void *user_data); - -/** - * Enumerate all entries that will be reached by the 'forward' button - * - * \param history The history object to enumerate in - * \param cb The callback function - * \param user_data Data passed to the callback - */ -void history_enumerate_forward( struct history *history, - history_enumerate_cb cb, void *user_data ); - -/** - * Enumerate all entries that will be reached by the 'back' button - * - * \param history The history object to enumerate in - * \param cb The callback function - * \param user_data Data passed to the callback - */ -void history_enumerate_back( struct history *history, - 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 - */ -const char *history_entry_get_url(const struct history_entry *entry); - -/** - * Returns the URL to a history entry - * - * \param entry the history entry to retrieve the fragment id from - * \return the fragment id - */ -const char *history_entry_get_fragment_id(const struct history_entry *entry); - -/** - * Returns the title of a history entry - * - * \param entry the history entry to retrieve the title from - * \return the title - */ -const char *history_entry_get_title(const struct history_entry *entry); - -/** - * Open a history entry in the specified browser window - * - * \param bw browser window - * \param history history containing entry - * \param entry entry to open - * \param new_window open entry in new window - */ -void history_go(struct browser_window *bw, struct history *history, - struct history_entry *entry, bool new_window); - -#endif diff --git a/desktop/mouse.h b/desktop/mouse.h index 9a3a16702..083bd1731 100644 --- a/desktop/mouse.h +++ b/desktop/mouse.h @@ -27,7 +27,7 @@ /* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS). * 2 is secondary mouse button (e.g. Adjust on RISC OS). */ -typedef enum { +typedef enum browser_mouse_state { BROWSER_MOUSE_HOVER = 0, /* No mouse buttons pressed, * May be used to indicate * hover or end of drag. */ @@ -78,13 +78,14 @@ typedef enum { } browser_mouse_state; -typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET, - GUI_POINTER_MENU, GUI_POINTER_UP, GUI_POINTER_DOWN, - GUI_POINTER_LEFT, GUI_POINTER_RIGHT, GUI_POINTER_RU, - GUI_POINTER_LD, GUI_POINTER_LU, GUI_POINTER_RD, - GUI_POINTER_CROSS, GUI_POINTER_MOVE, GUI_POINTER_WAIT, - GUI_POINTER_HELP, GUI_POINTER_NO_DROP, GUI_POINTER_NOT_ALLOWED, - GUI_POINTER_PROGRESS } gui_pointer_shape; +typedef enum gui_pointer_shape { + GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET, + GUI_POINTER_MENU, GUI_POINTER_UP, GUI_POINTER_DOWN, + GUI_POINTER_LEFT, GUI_POINTER_RIGHT, GUI_POINTER_RU, + GUI_POINTER_LD, GUI_POINTER_LU, GUI_POINTER_RD, + GUI_POINTER_CROSS, GUI_POINTER_MOVE, GUI_POINTER_WAIT, + GUI_POINTER_HELP, GUI_POINTER_NO_DROP, GUI_POINTER_NOT_ALLOWED, + GUI_POINTER_PROGRESS } gui_pointer_shape; /** Mouse pointer type */ typedef enum { diff --git a/desktop/netsurf.c b/desktop/netsurf.c index fa026dc6a..579648bae 100644 --- a/desktop/netsurf.c +++ b/desktop/netsurf.c @@ -29,7 +29,7 @@ #include "utils/config.h" #include "utils/utsname.h" #include "content/content_factory.h" -#include "content/fetch.h" +#include "content/fetchers.h" #include "content/hlcache.h" #include "content/mimesniff.h" #include "content/urldb.h" @@ -37,9 +37,9 @@ #include "image/image.h" #include "image/image_cache.h" #include "desktop/netsurf.h" -#include "desktop/401login.h" #include "desktop/browser.h" -#include "desktop/gui.h" +#include "desktop/system_colour.h" +#include "desktop/gui_factory.h" #include "utils/nsoption.h" #include "desktop/searchweb.h" @@ -67,13 +67,24 @@ */ #define SPECULATE_SMALL 4096 -/* the time between cache clean runs in ms */ +/** the time between image cache clean runs in ms. */ #define IMAGE_CACHE_CLEAN_TIME (10 * 1000) +/** default time between content cache cleans. */ #define HL_CACHE_CLEAN_TIME (2 * IMAGE_CACHE_CLEAN_TIME) +/** default minimum object time before object is pushed to backing store. */ +#define LLCACHE_MIN_DISC_LIFETIME (60 * 30) + +/** default maximum bandwidth for backing store writeout. */ +#define LLCACHE_MAX_DISC_BANDWIDTH (128 * 1024) + +/** ensure there is a minimal amount of memory for source objetcs and + * decoded bitmaps. + */ +#define MINIMUM_MEMORY_CACHE_SIZE (2 * 1024 * 1024) + bool netsurf_quit = false; -bool verbose_log = false; static void netsurf_lwc_iterator(lwc_string *str, void *pw) { @@ -94,14 +105,14 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query, { switch (query->type) { case LLCACHE_QUERY_AUTH: - gui_401login_open(query->url, query->data.auth.realm, cb, cbpw); + guit->browser->login(query->url, query->data.auth.realm, cb, cbpw); break; case LLCACHE_QUERY_REDIRECT: /** \todo Need redirect query dialog */ /* For now, do nothing, as this query type isn't emitted yet */ break; case LLCACHE_QUERY_SSL: - gui_cert_verify(query->url, query->data.ssl.certs, + guit->browser->cert_verify(query->url, query->data.ssl.certs, query->data.ssl.num, cb, cbpw); break; } @@ -109,20 +120,25 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query, return NSERROR_OK; } -#define MINIMUM_MEMORY_CACHE_SIZE (2 * 1024 * 1024) - -/** - * Initialise components used by gui NetSurf. - */ +/* exported interface documented in desktop/netsurf.h */ +nserror netsurf_register(struct netsurf_table *table) +{ + /* register the operation handlers */ + return gui_factory_register(table); +} -nserror netsurf_init(const char *messages) +/* exported interface documented in desktop/netsurf.h */ +nserror netsurf_init(const char *messages, const char *store_path) { - nserror error; + nserror ret; struct utsname utsname; - nserror ret = NSERROR_OK; struct hlcache_parameters hlcache_parameters = { .bg_clean_time = HL_CACHE_CLEAN_TIME, - .cb = netsurf_llcache_query_handler, + .llcache = { + .cb = netsurf_llcache_query_handler, + .minimum_lifetime = LLCACHE_MIN_DISC_LIFETIME, + .bandwidth = LLCACHE_MAX_DISC_BANDWIDTH, + } }; struct image_cache_parameters image_cache_parameters = { .bg_clean_time = IMAGE_CACHE_CLEAN_TIME, @@ -152,70 +168,86 @@ nserror netsurf_init(const char *messages) messages_load(messages); /* corestrings init */ - error = corestrings_init(); - if (error != NSERROR_OK) - return error; + ret = corestrings_init(); + if (ret != NSERROR_OK) + return ret; /* set up cache limits based on the memory cache size option */ - hlcache_parameters.limit = nsoption_int(memory_cache_size); + hlcache_parameters.llcache.limit = nsoption_int(memory_cache_size); - if (hlcache_parameters.limit < MINIMUM_MEMORY_CACHE_SIZE) { - hlcache_parameters.limit = MINIMUM_MEMORY_CACHE_SIZE; - LOG(("Setting minimum memory cache size to %d", - hlcache_parameters.limit)); + if (hlcache_parameters.llcache.limit < MINIMUM_MEMORY_CACHE_SIZE) { + hlcache_parameters.llcache.limit = MINIMUM_MEMORY_CACHE_SIZE; + LOG(("Setting minimum memory cache size %d", + hlcache_parameters.llcache.limit)); } /* image cache is 25% of total memory cache size */ - image_cache_parameters.limit = (hlcache_parameters.limit * 25) / 100; + image_cache_parameters.limit = (hlcache_parameters.llcache.limit * 25) / 100; /* image cache hysteresis is 20% of the image cache size */ image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100; /* account for image cache use from total */ - hlcache_parameters.limit -= image_cache_parameters.limit; + hlcache_parameters.llcache.limit -= image_cache_parameters.limit; + + /* set backing store target limit */ + hlcache_parameters.llcache.store.limit = nsoption_uint(disc_cache_size); + + /* set backing store hysterissi to 20% */ + hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;; + + /* set the path to the backing store */ + hlcache_parameters.llcache.store.path = store_path; /* image handler bitmap cache */ - error = image_cache_init(&image_cache_parameters); - if (error != NSERROR_OK) - return error; + ret = image_cache_init(&image_cache_parameters); + if (ret != NSERROR_OK) + return ret; /* content handler initialisation */ - error = nscss_init(); - if (error != NSERROR_OK) - return error; + ret = nscss_init(); + if (ret != NSERROR_OK) + return ret; - error = html_init(); - if (error != NSERROR_OK) - return error; + ret = html_init(); + if (ret != NSERROR_OK) + return ret; - error = image_init(); - if (error != NSERROR_OK) - return error; + ret = image_init(); + if (ret != NSERROR_OK) + return ret; - error = textplain_init(); - if (error != NSERROR_OK) - return error; + ret = textplain_init(); + if (ret != NSERROR_OK) + return ret; - error = mimesniff_init(); - if (error != NSERROR_OK) - return error; + ret = mimesniff_init(); + if (ret != NSERROR_OK) + return ret; url_init(); setlocale(LC_ALL, "C"); - fetch_init(); + /* initialise the fetchers */ + ret = fetcher_init(); + if (ret != NSERROR_OK) + return ret; /* Initialise the hlcache and allow it to init the llcache for us */ - hlcache_initialise(&hlcache_parameters); + ret = hlcache_initialise(&hlcache_parameters); + if (ret != NSERROR_OK) + return ret; /* Initialize system colours */ - gui_system_colour_init(); + ret = ns_system_colour_init(); + if (ret != NSERROR_OK) + return ret; js_initialise(); - return ret; + return NSERROR_OK; } @@ -225,8 +257,7 @@ nserror netsurf_init(const char *messages) int netsurf_main_loop(void) { while (!netsurf_quit) { - gui_poll(fetch_active); - hlcache_poll(); + guit->browser->poll(false); } return 0; @@ -241,19 +272,19 @@ void netsurf_exit(void) hlcache_stop(); LOG(("Closing GUI")); - gui_quit(); + guit->browser->quit(); LOG(("Finalising JavaScript")); js_finalise(); - LOG(("Closing search and related resources")); - search_web_cleanup(); + LOG(("Finalising Web Search")); + search_web_finalise(); LOG(("Finalising high-level cache")); hlcache_finalise(); LOG(("Closing fetches")); - fetch_quit(); + fetcher_quit(); mimesniff_fini(); @@ -270,7 +301,7 @@ void netsurf_exit(void) urldb_destroy(); LOG(("Destroying System colours")); - gui_system_colour_finalize(); + ns_system_colour_finalize(); corestrings_fini(); LOG(("Remaining lwc strings:")); @@ -278,5 +309,3 @@ void netsurf_exit(void) LOG(("Exited successfully")); } - - diff --git a/desktop/netsurf.h b/desktop/netsurf.h index bfdb647ff..6c6a22a86 100644 --- a/desktop/netsurf.h +++ b/desktop/netsurf.h @@ -23,13 +23,37 @@ #include "utils/errors.h" extern bool netsurf_quit; -extern bool verbose_log; extern const char * const netsurf_version; extern const int netsurf_version_major; extern const int netsurf_version_minor; -nserror netsurf_init(const char *messages); -extern void netsurf_exit(void); +struct netsurf_table; + +/** + * Register operation table. + * + * @param table NetSurf operations table. + * @return NSERROR_OK on success or error code on faliure. + */ +nserror netsurf_register(struct netsurf_table *table); + +/** + * Initialise netsurf core. + * + * @param messages path to translation mesage file. + * @return NSERROR_OK on success or error code on faliure. + */ +nserror netsurf_init(const char *messages, const char *store_path); + +/** + * Run event loop. + */ extern int netsurf_main_loop(void); +/** + * Finalise NetSurf core + */ +extern void netsurf_exit(void); + + #endif diff --git a/desktop/options.h b/desktop/options.h index 391dfbc08..33ecb7554 100644 --- a/desktop/options.h +++ b/desktop/options.h @@ -89,7 +89,7 @@ NSOPTION_STRING(accept_charset, NULL) NSOPTION_INTEGER(memory_cache_size, 12 * 1024 * 1024) /** Preferred expiry size of disc cache / bytes. */ -NSOPTION_INTEGER(disc_cache_size, 1024 * 1024 * 1024) +NSOPTION_UINT(disc_cache_size, 1024 * 1024 * 1024) /** Preferred expiry age of disc cache / days. */ NSOPTION_INTEGER(disc_cache_age, 28) diff --git a/desktop/plotters.h b/desktop/plotters.h index 448cedef5..c34692433 100644 --- a/desktop/plotters.h +++ b/desktop/plotters.h @@ -24,8 +24,9 @@ #define _NETSURF_DESKTOP_PLOTTERS_H_ #include <stdbool.h> -#include "css/css.h" -#include "content/content.h" +#include <stdio.h> + +#include "utils/types.h" #include "desktop/plot_style.h" struct bitmap; diff --git a/desktop/save_complete.c b/desktop/save_complete.c index 0c67654a6..71187eb10 100644 --- a/desktop/save_complete.c +++ b/desktop/save_complete.c @@ -21,8 +21,6 @@ * Save HTML document with dependencies (implementation). */ -#include "utils/config.h" - #include <assert.h> #include <ctype.h> #include <errno.h> @@ -30,20 +28,24 @@ #include <string.h> #include <sys/types.h> #include <regex.h> - #include <dom/dom.h> -#include "content/content.h" -#include "content/hlcache.h" -#include "css/css.h" -#include "desktop/save_complete.h" -#include "render/box.h" -#include "render/html.h" +#include "utils/config.h" #include "utils/corestrings.h" #include "utils/log.h" #include "utils/nsurl.h" #include "utils/utf8.h" #include "utils/utils.h" +#include "utils/file.h" +#include "utils/messages.h" +#include "content/content.h" +#include "content/hlcache.h" +#include "css/css.h" +#include "render/box.h" +#include "render/html.h" + +#include "desktop/gui_factory.h" +#include "desktop/save_complete.h" regex_t save_complete_import_re; @@ -142,19 +144,19 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx, const char *leafname, const char *data, size_t data_len, lwc_string *mime_type) { + nserror ret; FILE *fp; - bool error; - char fullpath[PATH_MAX]; + char *fname = NULL; - strncpy(fullpath, ctx->path, sizeof fullpath); - error = path_add_part(fullpath, sizeof fullpath, leafname); - if (error == false) { - warn_user("NoMemory", NULL); + ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, leafname); + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); return false; } - fp = fopen(fullpath, "wb"); + fp = fopen(fname, "wb"); if (fp == NULL) { + free(fname); LOG(("fopen(): errno = %i", errno)); warn_user("SaveError", strerror(errno)); return false; @@ -164,8 +166,10 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx, fclose(fp); - if (ctx->set_type != NULL) - ctx->set_type(fullpath, mime_type); + if (ctx->set_type != NULL) { + ctx->set_type(fname, mime_type); + } + free(fname); return true; } @@ -351,8 +355,11 @@ static bool save_complete_save_imported_sheets(save_complete_ctx *ctx, uint32_t i; for (i = 0; i < import_count; i++) { - if (save_complete_save_stylesheet(ctx, imports[i].c) == false) - return false; + /* treat a valid content as a stylesheet to save */ + if ((imports[i].c != NULL) && + (save_complete_save_stylesheet(ctx, imports[i].c) == false)) { + return false; + } } return true; @@ -435,7 +442,7 @@ static bool save_complete_save_html_objects(save_complete_ctx *ctx, object = html_get_objects(c, &count); for (; object != NULL; object = object->next) { - if (object->content != NULL) { + if ((object->content != NULL) && (object->box != NULL)) { if (save_complete_save_html_object(ctx, object->content) == false) return false; @@ -546,7 +553,6 @@ static bool save_complete_rewrite_url_value(save_complete_ctx *ctx, hlcache_handle *content; char *escaped; nserror error; - utf8_convert_ret ret; error = nsurl_join(ctx->base, value, &url); if (error == NSERROR_NOMEM) @@ -561,11 +567,11 @@ static bool save_complete_rewrite_url_value(save_complete_ctx *ctx, fprintf(ctx->fp, "\"%p\"", content); } else { /* no match found */ - ret = utf8_to_html(nsurl_access(url), "UTF-8", + error = utf8_to_html(nsurl_access(url), "UTF-8", nsurl_length(url), &escaped); nsurl_unref(url); - if (ret != UTF8_CONVERT_OK) + if (error != NSERROR_OK) return false; fprintf(ctx->fp, "\"%s\"", escaped); @@ -573,8 +579,8 @@ static bool save_complete_rewrite_url_value(save_complete_ctx *ctx, free(escaped); } } else { - ret = utf8_to_html(value, "UTF-8", value_len, &escaped); - if (ret != UTF8_CONVERT_OK) + error = utf8_to_html(value, "UTF-8", value_len, &escaped); + if (error != NSERROR_OK) return false; fprintf(ctx->fp, "\"%s\"", escaped); @@ -589,10 +595,10 @@ static bool save_complete_write_value(save_complete_ctx *ctx, const char *value, size_t value_len) { char *escaped; - utf8_convert_ret ret; + nserror ret; ret = utf8_to_html(value, "UTF-8", value_len, &escaped); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return false; fprintf(ctx->fp, "\"%s\"", escaped); @@ -918,7 +924,7 @@ static bool save_complete_node_handler(dom_node *node, save_complete_ctx *ctx = ctxin; dom_node_type type; dom_exception error; - utf8_convert_ret ret; + nserror ret; error = dom_node_get_node_type(node, &type); if (error != DOM_NO_ERR) @@ -952,7 +958,7 @@ static bool save_complete_node_handler(dom_node *node, ret = utf8_to_html(text_data, "UTF-8", text_len, &escaped); - if (ret != UTF8_CONVERT_OK) + if (ret != NSERROR_OK) return false; fwrite(escaped, sizeof(*escaped), @@ -1034,29 +1040,30 @@ static bool save_complete_node_handler(dom_node *node, static bool save_complete_save_html_document(save_complete_ctx *ctx, hlcache_handle *c, bool index) { - bool error; + nserror ret; FILE *fp; + char *fname = NULL; dom_document *doc; lwc_string *mime_type; char filename[32]; - char fullpath[PATH_MAX]; - strncpy(fullpath, ctx->path, sizeof fullpath); - - if (index) + if (index) { snprintf(filename, sizeof filename, "index"); - else + } else { snprintf(filename, sizeof filename, "%p", c); + } - error = path_add_part(fullpath, sizeof fullpath, filename); - if (error == false) { - warn_user("NoMemory", NULL); + ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, filename); + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), NULL); return false; } - fp = fopen(fullpath, "wb"); + fp = fopen(fname, "wb"); if (fp == NULL) { - warn_user("NoMemory", NULL); + free(fname); + LOG(("fopen(): errno = %i", errno)); + warn_user("SaveError", strerror(errno)); return false; } @@ -1068,6 +1075,7 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx, if (save_complete_libdom_treewalk((dom_node *) doc, save_complete_node_handler, ctx) == false) { + free(fname); warn_user("NoMemory", 0); fclose(fp); return false; @@ -1078,10 +1086,11 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx, mime_type = content_get_mime_type(c); if (mime_type != NULL) { if (ctx->set_type != NULL) - ctx->set_type(fullpath, mime_type); + ctx->set_type(fname, mime_type); lwc_string_unref(mime_type); } + free(fname); return true; } @@ -1119,19 +1128,18 @@ static bool save_complete_save_html(save_complete_ctx *ctx, hlcache_handle *c, static bool save_complete_inventory(save_complete_ctx *ctx) { + nserror ret; FILE *fp; - bool error; + char *fname = NULL; save_complete_entry *entry; - char fullpath[PATH_MAX]; - strncpy(fullpath, ctx->path, sizeof fullpath); - error = path_add_part(fullpath, sizeof fullpath, "Inventory"); - if (error == false) { - warn_user("NoMemory", NULL); + ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, "Inventory"); + if (ret != NSERROR_OK) { return false; } - fp = fopen(fullpath, "w"); + fp = fopen(fname, "w"); + free(fname); if (fp == NULL) { LOG(("fopen(): errno = %i", errno)); warn_user("SaveError", strerror(errno)); @@ -1193,8 +1201,9 @@ bool save_complete(hlcache_handle *c, const char *path, result = save_complete_save_html(&ctx, c, true); - if (result) + if (result) { result = save_complete_inventory(&ctx); + } save_complete_ctx_finalise(&ctx); diff --git a/desktop/save_text.c b/desktop/save_text.c index 92cf32a9f..bc4d4c57a 100644 --- a/desktop/save_text.c +++ b/desktop/save_text.c @@ -28,14 +28,16 @@ #include <dom/dom.h> #include "utils/config.h" +#include "utils/log.h" +#include "utils/utf8.h" +#include "utils/utils.h" #include "content/content.h" #include "content/hlcache.h" -#include "desktop/save_text.h" #include "render/box.h" #include "render/html.h" -#include "utils/log.h" -#include "utils/utf8.h" -#include "utils/utils.h" + +#include "desktop/gui_factory.h" +#include "desktop/save_text.h" static void extract_text(struct box *box, bool *first, save_text_whitespace *before, struct save_text_state *save); @@ -58,7 +60,7 @@ void save_as_text(hlcache_handle *c, char *path) struct save_text_state save = { NULL, 0, 0 }; save_text_whitespace before = WHITESPACE_NONE; bool first = true; - utf8_convert_ret ret; + nserror ret; char *result; if (!c || content_get_type(c) != CONTENT_HTML) { @@ -69,10 +71,10 @@ void save_as_text(hlcache_handle *c, char *path) if (!save.block) return; - ret = utf8_to_local_encoding(save.block, save.length, &result); + ret = guit->utf8->utf8_to_local(save.block, save.length, &result); free(save.block); - if (ret != UTF8_CONVERT_OK) { + if (ret != NSERROR_OK) { LOG(("failed to convert to local encoding, return %d", ret)); return; } diff --git a/desktop/scrollbar.c b/desktop/scrollbar.c index d24ea727a..dadb82801 100644 --- a/desktop/scrollbar.c +++ b/desktop/scrollbar.c @@ -25,6 +25,7 @@ #include <stdbool.h> #include <stdlib.h> +#include "desktop/system_colour.h" #include "desktop/mouse.h" #include "desktop/scrollbar.h" #include "utils/nsoption.h" @@ -190,9 +191,9 @@ bool scrollbar_redraw(struct scrollbar *s, int x, int y, int v[6]; /* array of triangle vertices */ int x0, y0, x1, y1; - colour bg_fill_colour = gui_system_colour_char("Scrollbar"); - colour fg_fill_colour = gui_system_colour_char("ButtonFace"); - colour arrow_fill_colour = gui_system_colour_char("ButtonText"); + colour bg_fill_colour = ns_system_colour_char("Scrollbar"); + colour fg_fill_colour = ns_system_colour_char("ButtonFace"); + colour arrow_fill_colour = ns_system_colour_char("ButtonText"); plot_style_t bg_fill_style = { .fill_type = PLOT_OP_TYPE_SOLID, diff --git a/desktop/search.c b/desktop/search.c index 3a7c768a5..201d416dd 100644 --- a/desktop/search.c +++ b/desktop/search.c @@ -21,67 +21,27 @@ /** \file * Free text search (core) */ -#include "utils/config.h" -#include <ctype.h> -#include <string.h> -#include <dom/dom.h> #include "content/content.h" -#include "content/hlcache.h" + #include "desktop/browser_private.h" -#include "desktop/gui.h" -#include "utils/nsoption.h" #include "desktop/search.h" -#include "desktop/selection.h" -#include "render/box.h" -#include "render/html.h" -#include "render/search.h" -#include "render/textplain.h" -#include "utils/config.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/url.h" -#include "utils/utils.h" - - - -/** - * Starts or continues an existing search. - * - * \param bw the browser_window to search - * \param callbacks callbacks vtable to update frontend according to results - * \param gui_data a pointer returned to the callbacks - * \param flags search flags - * \param string string to search for - */ -void browser_window_search(struct browser_window *bw, - struct gui_search_callbacks *gui_callbacks, void *gui_data, +/* exported function documented in desktop/search.h */ +void browser_window_search(struct browser_window *bw, void *context, search_flags_t flags, const char *string) { - assert(gui_callbacks != NULL); - - if (bw == NULL || bw->current_content == NULL) - return; - - content_search(bw->current_content, gui_callbacks, gui_data, - flags, string); + if ((bw != NULL) && + (bw->current_content != NULL)) { + content_search(bw->current_content, context, flags, string); + } } - -/** - * Clear up a search. Frees any memory used by the search - * - * \param bw the browser_window to search - * \param callbacks callbacks vtable to update frontend according to results - * \param gui_data a pointer returned to the callbacks - * \param flags search flags - * \param string string to search for - */ +/* exported function documented in desktop/search.h */ void browser_window_search_clear(struct browser_window *bw) { - if (bw == NULL || bw->current_content == NULL) - return; - - content_search_clear(bw->current_content); + if ((bw != NULL) && + (bw->current_content != NULL)) { + content_search_clear(bw->current_content); + } } diff --git a/desktop/search.h b/desktop/search.h index 8440ce982..254acde99 100644 --- a/desktop/search.h +++ b/desktop/search.h @@ -33,54 +33,24 @@ typedef enum { } search_flags_t; /** - * Change the displayed search status. - * \param found search pattern matched in text - * \param p gui private data pointer provided with search callbacks - */ -typedef void (*gui_search_status)(bool found, void *p); - -/** - * display hourglass while searching - * \param active start/stop indicator - * \param p gui private data pointer provided with search callbacks - */ -typedef void (*gui_search_hourglass)(bool active, void *p); - -/** - * add search string to recent searches list - * front has full liberty how to implement the bare notification; - * core gives no guarantee of the integrity of the const char * - * \param string search pattern - * \param p gui private data pointer provided with search callbacks - */ -typedef void (*gui_search_add_recent)(const char *string, void *p); - -/** - * activate search forwards button in gui - * \param active activate/inactivate - * \param p gui private data pointer provided with search callbacks + * Starts or continues an existing search. + * + * \param bw The browser_window to search. + * \param context A context pointer passed to the callbacks. + * \param flags Flags controlling the search operation. + * \param string The string being searched for. */ -typedef void (*gui_search_forward_state)(bool active, void *p); +void browser_window_search(struct browser_window *bw, void *context, search_flags_t flags, const char *string); /** - * activate search back button in gui - * \param active activate/inactivate - * \param p gui private data pointer provided with search callbacks + * Clear up a search. + * + * Frees any memory used by the search. + * + * \param bw The browser window to clean up the search for. + * \param context A context pointer passed to the callbacks. */ -typedef void (*gui_search_back_state)(bool active, void *p); - -struct gui_search_callbacks { - gui_search_forward_state forward_state; - gui_search_back_state back_state; - gui_search_status status; - gui_search_hourglass hourglass; - gui_search_add_recent add_recent; -}; - -void browser_window_search(struct browser_window *bw, - struct gui_search_callbacks *gui_callbacks, void *gui_data, - search_flags_t flags, const char *string); void browser_window_search_clear(struct browser_window *bw); #endif diff --git a/desktop/searchweb.c b/desktop/searchweb.c index 87e3e21f1..dc12170c1 100644 --- a/desktop/searchweb.c +++ b/desktop/searchweb.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -15,320 +15,549 @@ * 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 - * web search (core) + +/** + * \file desktop/searchweb.c + * \brief core web search facilities implementation. */ -#include "utils/config.h" -#include <ctype.h> -#include <string.h> -#include "content/content.h" -#include "content/hlcache.h" -#include "desktop/browser.h" -#include "desktop/gui.h" -#include "utils/nsoption.h" -#include "desktop/searchweb.h" -#include "utils/config.h" #include "utils/log.h" -#include "utils/messages.h" #include "utils/url.h" -#include "utils/utils.h" +#include "utils/nsoption.h" +#include "content/hlcache.h" -static struct search_provider { +#include "desktop/gui_factory.h" +#include "desktop/searchweb.h" + +struct search_provider { char *name; /**< readable name such as 'google', 'yahoo', etc */ char *hostname; /**< host address such as www.google.com */ char *searchstring; /** < such as "www.google.com?search=%s" */ char *ico; /** < location of domain's favicon */ -} current_search_provider; + hlcache_handle *ico_handle; +}; -static hlcache_handle *search_ico = NULL; -char *search_engines_file_location; -char *search_default_ico_location; +static struct search_web_ctx_s { + struct search_provider *providers; /* web search providers */ + size_t providers_count; /* number of providers */ -#ifdef WITH_BMP -static nserror search_web_ico_callback(hlcache_handle *ico, - const hlcache_event *event, void *pw); -#endif + size_t current; /* current provider */ -/** - * creates a new browser window according to the search term - * \param searchterm such as "my search term" - */ + hlcache_handle *default_ico_handle; -bool search_web_new_window(struct browser_window *bw, const char *searchterm) +} search_web_ctx; + + +static const char *default_providers = "Google|www.google.com|http://www.google.com/search?q=%s|http://www.google.com/favicon.ico|\n"; + +static const char *default_search_icon_url = "resource:icons/search.png"; + + +/** + * Read providers file. + * + * Allocates stoage of sufficient size for the providers file and + * reads the entire file in. + * + * \param fname The filename to read. + * \param providers_out A pointer to place the result buffer in. + * \param providers_size_out Size of buffer. + * \return NSERROR_OK and providers_out updated or appropriate error code. + */ +static nserror +read_providers(const char *fname, + char **providers_out, + size_t *providers_size_out) { - char *encsearchterm; - char *urltxt; - nsurl *url; - nserror error; + FILE *providersf; + long ftellsize; + size_t fsize; + char *providersd; - if (url_escape(searchterm,0, true, NULL, &encsearchterm) != URL_FUNC_OK) - return false; + if (fname == NULL) { + return NSERROR_BAD_PARAMETER; + } - urltxt = search_web_get_url(encsearchterm); - free(encsearchterm); + providersf = fopen(fname, "r"); + if (providersf == NULL) { + return NSERROR_NOT_FOUND; + } - error = nsurl_create(urltxt, &url); - if (error == NSERROR_OK) { - error = browser_window_create(BROWSER_WINDOW_VERIFIABLE | - BROWSER_WINDOW_HISTORY | - BROWSER_WINDOW_TAB, - url, - NULL, - bw, - NULL); - nsurl_unref(url); + if (fseek(providersf, 0, SEEK_END) != 0) { + fclose(providersf); + return NSERROR_INVALID; } - if (error != NSERROR_OK) { - warn_user(messages_get_errorcode(error), 0); + + ftellsize = ftell(providersf); + if (ftellsize < 0) { + fclose(providersf); + return NSERROR_INVALID; } + fsize = ftellsize; - free(urltxt); - return true; -} + if (fseek(providersf, 0, SEEK_SET) != 0) { + fclose(providersf); + return NSERROR_INVALID; + } -/** simplistic way of checking whether an entry from the url bar is an - * url / a search; could be improved to properly test terms - */ + providersd = malloc(fsize + 1); + if (providersd == NULL) { + fclose(providersf); + return NSERROR_NOMEM; + } -bool search_is_url(const char *url) -{ - /** \todo Implement this properly */ + if (fread(providersd, 1, fsize, providersf) != fsize) { + fclose(providersf); + free(providersd); + return NSERROR_BAD_SIZE; + } + providersd[fsize] = 0; /* ensure null terminated */ - /* For now, everything is an URL */ - return true; -} + fclose(providersf); -/** - * caches the details of the current web search provider - * \param reference the enum value of the provider - * browser init code [as well as changing preferences code] should call - * search_web_provider_details(option_search_provider) - */ + *providers_out = providersd; + *providers_size_out = fsize; -void search_web_provider_details(int reference) -{ - char buf[300]; - int ref = 0; - FILE *f; - if (search_engines_file_location == NULL) - return; - f = fopen(search_engines_file_location, "r"); - if (f == NULL) - return; - while (fgets(buf, sizeof(buf), f) != NULL) { - if (buf[0] == '\0') - continue; - buf[strlen(buf)-1] = '\0'; - if (ref++ == (int)reference) - break; - } - fclose(f); - if (current_search_provider.name != NULL) - free(current_search_provider.name); - current_search_provider.name = strdup(strtok(buf, "|")); - if (current_search_provider.hostname != NULL) - free(current_search_provider.hostname); - current_search_provider.hostname = strdup(strtok(NULL, "|")); - if (current_search_provider.searchstring != NULL) - free(current_search_provider.searchstring); - current_search_provider.searchstring = strdup(strtok(NULL, "|")); - if (current_search_provider.ico != NULL) - free(current_search_provider.ico); - current_search_provider.ico = strdup(strtok(NULL, "|")); - return; + return NSERROR_OK; } /** - * escapes a search term then creates the appropriate url from it + * parse search providers from a memory block. + * + * \param providersd The provider info data. + * \param providers_size The size of the provider data. + * \param providers_out The resulting provider array. + * \param providers_count The number of providers in the output array. + * \return NSERROR_OK on success or error code on faliure. */ - -char *search_web_from_term(const char *searchterm) +static nserror +parse_providers(char *providersd, + size_t providers_size, + struct search_provider **providers_out, + size_t *providers_count) { - char *encsearchterm, *url; - if (url_escape(searchterm, 0, true, NULL, &encsearchterm) - != URL_FUNC_OK) - return strdup(searchterm); - url = search_web_get_url(encsearchterm); - free(encsearchterm); - return url; -} + size_t pcount = 0; /* number of providers */ + size_t pidx; + char *nl = providersd; + struct search_provider *providers; + + /* count newlines */ + while (nl != NULL) { + nl = strchr(nl, '\n'); + if (nl != NULL) { + nl++; + pcount+=1; + } + } -/** accessor for global search provider name */ + if (pcount == 0) { + return NSERROR_INVALID; + } -char *search_web_provider_name(void) -{ - if (current_search_provider.name) - return strdup(current_search_provider.name); - return strdup("google"); -} + providers = malloc(pcount * sizeof(*providers)); + if (providers == NULL) { + return NSERROR_NOMEM; + } -/** accessor for global search provider hostname */ + nl = providersd; + for (pidx = 0; pidx < pcount; pidx++) { + providers[pidx].name = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].hostname = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].searchstring = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].ico = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + /* skip newline */ + nl = strchr(nl, '\n'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + nl++; -char *search_web_provider_host(void) -{ - if (current_search_provider.hostname) - return strdup(current_search_provider.hostname); - return strdup("www.google.com"); -} + providers[pidx].ico_handle = NULL; + } -/** accessor for global search provider ico name */ + *providers_out = providers; + *providers_count = pcount; -char *search_web_ico_name(void) -{ - if (current_search_provider.ico) - return strdup(current_search_provider.ico); - return strdup("http://www.google.com/favicon.ico"); + return NSERROR_OK; } /** - * creates a full url from an encoded search term + * create a url for a search provider and a term + * + * \param The provider to use. + * \param term The term being searched for. + * \param url_out The resulting url. + * \return NSERROR_OK on sucess or appropriate error code. */ - -char *search_web_get_url(const char *encsearchterm) +static nserror +make_search_nsurl(struct search_provider *provider, + const char *term, + nsurl **url_out) { - char *pref, *ret; - int len; - if (current_search_provider.searchstring) - pref = strdup(current_search_provider.searchstring); - else - pref = strdup("http://www.google.com/search?q=%s"); - if (pref == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - len = strlen(encsearchterm) + strlen(pref); - ret = malloc(len -1); /* + '\0' - "%s" */ - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(pref); - return NULL; - } - snprintf(ret, len-1, pref, encsearchterm); - free(pref); - return ret; + nserror ret; + nsurl *url; + char *eterm; /* escaped term */ + char *searchstr; /* the providers search string */ + char *urlstr; /* the escaped term substituted into the provider */ + char *urlstro; + size_t urlstr_len; + + /* escape the search term and join it to the search url */ + ret = url_escape(term, 0, true, NULL, &eterm); + if (ret != NSERROR_OK) { + return ret; + } + + searchstr = provider->searchstring; + + urlstr_len = strlen(searchstr) + strlen(eterm) + 1; + urlstro = urlstr = malloc(urlstr_len); + if (urlstr == NULL) { + free(eterm); + return NSERROR_NOMEM; + } + + /* composite search url */ + for ( ; *searchstr != 0; searchstr++, urlstro++) { + *urlstro = *searchstr; + if ((*searchstr == '%') && (searchstr[1] == 's')) { + searchstr++; /* skip % */ + memcpy(urlstro, eterm, strlen(eterm)); + urlstro += strlen(eterm) - 1; + } + } + free(eterm); + *urlstro = '\0'; /* ensure string is NULL-terminated */ + + ret = nsurl_create(urlstr, &url); + free(urlstr); + if (ret != NSERROR_OK) { + return ret; + } + + *url_out = url; + return NSERROR_OK; } /** - * function to retrieve the search web ico, from cache / from local - * filesystem / from the web - * \param localdefault true when there is no appropriate favicon - * update the search_ico cache else delay until fetcher callback + * callback for hlcache icon fetch events. */ +static nserror +search_web_ico_callback(hlcache_handle *ico, + const hlcache_event *event, + void *pw) +{ + struct search_provider *provider = pw; + + switch (event->type) { + + case CONTENT_MSG_DONE: + LOG(("icon '%s' retrived", + nsurl_access(hlcache_handle_get_url(ico)))); + guit->search_web->provider_update(provider->name, + content_get_bitmap(ico)); + break; + + case CONTENT_MSG_ERROR: + LOG(("icon %s error: %s", + nsurl_access(hlcache_handle_get_url(ico)), + event->data.error)); + hlcache_handle_release(ico); + /* clear reference to released handle */ + provider->ico_handle = NULL; + break; + + default: + break; + } -void search_web_retrieve_ico(bool localdefault) + return NSERROR_OK; +} + +/* exported interface documented in desktop/searchweb.h */ +nserror +search_web_omni(const char *term, + enum search_web_omni_flags flags, + struct nsurl **url_out) { -#if !defined(WITH_BMP) - /* This function is of limited use when no BMP support - * is enabled, given the icons it is fetching are BMPs - * more often than not. This also avoids an issue where - * all this code goes mad if BMP support is not enabled. - */ - return; -#else - content_type accept = CONTENT_IMAGE; - char *url; - nserror error; - nsurl *icon_nsurl; + nserror ret; + nsurl *url; + char *eterm; /* encoded/altered search term */ + + if ((flags & SEARCH_WEB_OMNI_SEARCHONLY) == 0) { + + /* first check to see if the term is a url */ + ret = nsurl_create(term, &url); + if (ret == NSERROR_OK) { + *url_out = url; + return NSERROR_OK; + } + + /* try with adding default scheme */ + eterm = malloc(strlen(term) + SLEN("http://") + 1); + if (eterm == NULL) { + return NSERROR_NOMEM; + } + sprintf(eterm, "http://%s", term); + ret = nsurl_create(eterm, &url); + free(eterm); + if (ret == NSERROR_OK) { + *url_out = url; + return NSERROR_OK; + } - if (localdefault) { - if (search_default_ico_location == NULL) - return; - url = malloc(SLEN("file://") + strlen( - search_default_ico_location) + 1); - if (url == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; + /* do not pass to search if user has disabled the option */ + if (nsoption_bool(search_url_bar) == false) { + return NSERROR_BAD_URL; } - strcpy(url, "file://"); - strcat(url, search_default_ico_location); - } else { - url = search_web_ico_name(); } - if (url == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; } - error = nsurl_create(url, &icon_nsurl); - if (error != NSERROR_OK) { - free(url); - search_ico = NULL; - return; + /* turn search into a nsurl */ + ret = make_search_nsurl(&search_web_ctx.providers[search_web_ctx.current], term, &url); + if (ret != NSERROR_OK) { + return ret; } - error = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, - search_web_ico_callback, NULL, NULL, accept, - &search_ico); + *url_out = url; + return NSERROR_OK; +} - nsurl_unref(icon_nsurl); +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_select_provider(int selection) +{ + struct search_provider *provider; + struct bitmap *ico_bitmap = NULL; - if (error != NSERROR_OK) - search_ico = NULL; + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; + } - free(url); -#endif /* WITH_BMP */ -} + /* negative value just selects whatevers current */ + if (selection >= 0) { + /* ensure selection lies within acceptable range */ + if ((size_t)selection < search_web_ctx.providers_count) { + search_web_ctx.current = selection; + } else { + /* out of range */ + search_web_ctx.current = 0; + } + } -/** - * returns a reference to the static global search_ico [ / NULL] - * caller may adjust ico's settings; clearing / free()ing is the core's - * responsibility - */ + provider = &search_web_ctx.providers[search_web_ctx.current]; -hlcache_handle *search_web_ico(void) -{ - return search_ico; -} + /* set the icon now (if we can) at least to the default */ + if (provider->ico_handle != NULL) { + ico_bitmap = content_get_bitmap(provider->ico_handle); + } + if ((ico_bitmap == NULL) && + (search_web_ctx.default_ico_handle != NULL)) { + ico_bitmap = content_get_bitmap(search_web_ctx.default_ico_handle); + } + /* update the callback with the provider change. Bitmap may + * be NULL at this point. + */ + guit->search_web->provider_update(provider->name, ico_bitmap); -/** - * Cleans up any remaining resources during shutdown. - */ -void search_web_cleanup(void) -{ - if (search_ico != NULL) { - hlcache_handle_release(search_ico); - search_ico = NULL; + + /* if the providers icon has not been retrived get it now */ + if (provider->ico_handle == NULL) { + nsurl *icon_nsurl; + nserror ret; + + /* create search icon url */ + ret = nsurl_create(provider->ico, &icon_nsurl); + if (ret != NSERROR_OK) { + return ret; + } + + ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, + search_web_ico_callback, + provider, + NULL, CONTENT_IMAGE, + &provider->ico_handle); + nsurl_unref(icon_nsurl); + if (ret != NSERROR_OK) { + provider->ico_handle = NULL; + return ret; + } } + + return NSERROR_OK; } /** - * callback function to cache ico then notify front when successful - * else retry default from local file system + * callback for hlcache icon fetch events. */ - -#ifdef WITH_BMP -nserror search_web_ico_callback(hlcache_handle *ico, - const hlcache_event *event, void *pw) +static nserror +default_ico_callback(hlcache_handle *ico, + const hlcache_event *event, + void *pw) { + struct search_web_ctx_s *ctx = pw; + switch (event->type) { - case CONTENT_MSG_LOADING: - case CONTENT_MSG_READY: - break; case CONTENT_MSG_DONE: - LOG(("got favicon '%s'", nsurl_access(hlcache_handle_get_url(ico)))); - gui_window_set_search_ico(search_ico); + LOG(("default icon '%s' retrived", + nsurl_access(hlcache_handle_get_url(ico)))); + + /* only set to default icon if providers icon has no handle */ + if (ctx->providers[search_web_ctx.current].ico_handle == NULL) { + guit->search_web->provider_update( + ctx->providers[search_web_ctx.current].name, + content_get_bitmap(ico)); + } break; case CONTENT_MSG_ERROR: - LOG(("favicon %s error: %s", - nsurl_access(hlcache_handle_get_url(ico)), - event->data.error)); - hlcache_handle_release(search_ico); - search_ico = NULL; - search_web_retrieve_ico(true); + LOG(("icon %s error: %s", + nsurl_access(hlcache_handle_get_url(ico)), + event->data.error)); + hlcache_handle_release(ico); + /* clear reference to released handle */ + ctx->default_ico_handle = NULL; break; - case CONTENT_MSG_STATUS: + default: break; + } - default: - assert(0); + return NSERROR_OK; +} + +/* exported interface documented in desktop/searchweb.h */ +ssize_t search_web_iterate_providers(ssize_t from, const char **name) +{ + if (from < 0) + return -1; + + if ((size_t)from >= search_web_ctx.providers_count) + return -1; + + *name = search_web_ctx.providers[from].name; + + return from + 1; +} + + +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_init(const char *provider_fname) +{ + nserror ret; + char *providers; + size_t providers_size; + nsurl *icon_nsurl; + + /* create search icon url */ + ret = nsurl_create(default_search_icon_url, &icon_nsurl); + if (ret != NSERROR_OK) { + return ret; + } + + /* get a list of providers */ + ret = read_providers(provider_fname, &providers, &providers_size); + if (ret != NSERROR_OK) { + providers = strdup(default_providers); + if (providers == NULL) { + return NSERROR_NOMEM; + } + providers_size = strlen(providers); } + /* parse list of providers */ + ret = parse_providers(providers, + providers_size, + &search_web_ctx.providers, + &search_web_ctx.providers_count); + if (ret != NSERROR_OK) { + free(providers); + return ret; + } + + /* get default search icon */ + ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, + default_ico_callback, + &search_web_ctx, + NULL, CONTENT_IMAGE, + &search_web_ctx.default_ico_handle); + nsurl_unref(icon_nsurl); + if (ret != NSERROR_OK) { + search_web_ctx.default_ico_handle = NULL; + free(search_web_ctx.providers); + search_web_ctx.providers = NULL; + free(providers); + return ret; + } + + + return NSERROR_OK; +} + +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_finalise(void) +{ + size_t pidx; + + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; + } + + if (search_web_ctx.default_ico_handle != NULL) { + hlcache_handle_release(search_web_ctx.default_ico_handle); + } + for (pidx = 0; pidx < search_web_ctx.providers_count; pidx++) { + if (search_web_ctx.providers[pidx].ico_handle != NULL) { + hlcache_handle_release(search_web_ctx.providers[pidx].ico_handle); + } + } + + /* All the search provider data is held in a single block for + * efficiency. + */ + free(search_web_ctx.providers[0].name); + + free(search_web_ctx.providers); + search_web_ctx.providers = NULL; + return NSERROR_OK; } -#endif /* WITH_BMP */ diff --git a/desktop/searchweb.h b/desktop/searchweb.h index 3920f3c6e..b3b3902cf 100644 --- a/desktop/searchweb.h +++ b/desktop/searchweb.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,65 +16,105 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/** + * \file desktop/searchweb.h + * \brief core web search facilities interface. + */ + #ifndef _NETSURF_DESKTOP_SEARCH_WEB_H_ #define _NETSURF_DESKTOP_SEARCH_WEB_H_ -#include <ctype.h> -#include <stdbool.h> -#include <string.h> - -struct browser_window; -struct hlcache_handle; - -extern char *search_engines_file_location; -extern char *search_default_ico_location; +struct bitmap; /** - * open new tab/window for web search term + * Graphical user interface browser web search function table. + * */ -bool search_web_new_window(struct browser_window *bw, const char *searchterm); +struct gui_search_web_table { + /** + * called when the search provider details are updated. + * + * \param provider_name The name of the provider. + * \param ico_bitmap The bitmap of the search icon may be NULL + * if no icon is yet available. + */ + nserror (*provider_update)(const char *provider_name, struct bitmap *ico_bitmap); +}; /** - * retrieve full search url from unencoded search term + * Flags which alter the behaviour of the omin search. */ -char *search_web_from_term(const char *searchterm); +enum search_web_omni_flags { + SEARCH_WEB_OMNI_NONE = 0, /**< no changes to default operation */ + SEARCH_WEB_OMNI_SEARCHONLY = 1, /**< The search does not attempt to + * interpret the url as a url before + * using it as a search term. + */ +}; /** - * retrieve full search url from encoded web search term + * Generate a nsurl from a search term. + * + * This interface obtains a url appropriate for the given search + * term. The flags allow control over the operation. By default the + * operations are: + * - interpret the \a term as a url + * - if missing a scheme as a http: url + * - combined with the search providers url into a url for that provider. + * + * \param term The search term. + * \param flags Flags to control operation. + * \param url_out The ourput url on success. + * \return NSERROR_OK on success or appropriate error code. */ -char *search_web_get_url(const char *encsearchterm); +nserror search_web_omni(const char *term, enum search_web_omni_flags flags, struct nsurl **url_out); /** - * cache details of web search provider from file + * Change the currently selected web search provider. + * + * \param selection Index of the search provider to select or -1 to + * reselect the current provider + * \return NSERROR_OK on success or appropriate error code. */ -void search_web_provider_details(int reference); +nserror search_web_select_provider(int selection); -/** - * retrieve name of web search provider - */ -char *search_web_provider_name(void); /** - * retrieve hostname of web search provider + * Iterate the search providers, returning their names. + * + * \param from Index to start iteration from. Use 0 to begin iteration. + * Use the value returned from search_web_iterate_providers to + * continue an iteration. + * \param name Pointer to fill in with the search provider name requested. + * \return -1 if there are no more, otherwise the iterator for the next item. + * + * \verb + * ssize_t iter; + * const char *name; + * ... + * for (iter = search_web_iterate_providers(0, &name); + * iter != -1; + * iter = search_web_iterate_providers(iter, &name)) { + * do_something_with(name); + * } + * \endverb */ -char *search_web_provider_host(void); +ssize_t search_web_iterate_providers(ssize_t from, const char **name); + /** - * retrieve name of .ico for search bar + * Initialise the web search operations. + * + * \param provider_fname Path to web search providers file. + * \return NSERROR_OK on successful initialisation or appropriate error code. */ -char *search_web_ico_name(void); +nserror search_web_init(const char *provider_fname); /** - * check whether an URL is in fact a search term - * \param url the url being checked - * \return true for url, false for search + * Finalise the web search operations freeing all resources. + * + * \return NSERROR_OK on success or appropriate error code. */ -bool search_is_url(const char *url); - -void search_web_retrieve_ico(bool localdefault); - -struct hlcache_handle *search_web_ico(void); - -void search_web_cleanup(void); +nserror search_web_finalise(void); #endif diff --git a/desktop/selection.c b/desktop/selection.c index 13a1293e3..34292fdce 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -29,7 +29,7 @@ #include <dom/dom.h> #include "desktop/browser_private.h" -#include "desktop/gui.h" +#include "desktop/gui_factory.h" #include "desktop/mouse.h" #include "desktop/plotters.h" #include "desktop/save_text.h" @@ -274,7 +274,7 @@ bool selection_click(struct selection *s, browser_mouse_state mouse, (modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) { /* drag-saving selection */ char *sel = selection_get_copy(s); - gui_drag_save_selection(top->window, sel); + guit->window->drag_save_selection(top->window, sel); free(sel); } else if (!modkeys) { @@ -293,7 +293,7 @@ bool selection_click(struct selection *s, browser_mouse_state mouse, s->drag_state = DRAG_END; - gui_start_selection(top->window); + guit->window->start_selection(top->window); } else if (mouse & BROWSER_MOUSE_DRAG_2) { @@ -312,7 +312,7 @@ bool selection_click(struct selection *s, browser_mouse_state mouse, s->drag_state = DRAG_START; } - gui_start_selection(top->window); + guit->window->start_selection(top->window); } else if (mouse & BROWSER_MOUSE_CLICK_2) { @@ -844,7 +844,7 @@ bool selection_copy_to_clipboard(struct selection *s) return false; } - gui_set_clipboard(sel_string.buffer, sel_string.length, + guit->clipboard->set(sel_string.buffer, sel_string.length, sel_string.styles, sel_string.n_styles); free(sel_string.buffer); diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c index e0e87fbbe..5280e094a 100644 --- a/desktop/sslcert_viewer.c +++ b/desktop/sslcert_viewer.c @@ -24,9 +24,9 @@ #include <assert.h> #include <stdlib.h> - #include "content/fetch.h" #include "content/urldb.h" +#include "content/hlcache.h" #include "desktop/sslcert_viewer.h" #include "desktop/treeview.h" #include "utils/messages.h" @@ -47,7 +47,7 @@ enum sslcert_viewer_field { /** ssl certificate verification context. */ struct sslcert_session_data { - const struct ssl_cert_info *certs; /**< Certificates */ + struct ssl_cert_info *certs; /**< Certificates */ unsigned long num; /**< Number of certificates in chain */ nsurl *url; /**< The url of the certificate */ llcache_query_response cb; /**< Cert accept/reject callback */ @@ -394,8 +394,15 @@ static void sslcert_cleanup_session(struct sslcert_session_data *ssl_d) { assert(ssl_d != NULL); - if (ssl_d->url) + if (ssl_d->url) { nsurl_unref(ssl_d->url); + ssl_d->url = NULL; + } + + if (ssl_d->certs) { + free(ssl_d->certs); + ssl_d->certs = NULL; + } free(ssl_d); } @@ -439,12 +446,19 @@ nserror sslcert_viewer_create_session_data(unsigned long num, nsurl *url, data = malloc(sizeof(struct sslcert_session_data)); if (data == NULL) { - warn_user("NoMemory", 0); *ssl_d = NULL; return NSERROR_NOMEM; } - data->certs = certs; + /* copy certificate data */ + data->certs = malloc(num * sizeof(struct ssl_cert_info)); + if (data->certs == NULL) { + free(data); + *ssl_d = NULL; + return NSERROR_NOMEM; + } + memcpy(data->certs, certs, num * sizeof(struct ssl_cert_info)); + data->url = nsurl_ref(url); data->num = num; data->cb = cb; @@ -486,6 +500,9 @@ void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d, int x, int y, struct rect *clip, const struct redraw_context *ctx) { + assert(ssl_d != NULL && + "sslcert_viewer_redraw() given bad session data"); + treeview_redraw(ssl_d->tree, x, y, clip, ctx); } diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h index e02f095f5..d6b0c1b8b 100644 --- a/desktop/sslcert_viewer.h +++ b/desktop/sslcert_viewer.h @@ -24,7 +24,6 @@ #include <stdbool.h> #include <stdint.h> -#include "desktop/browser.h" #include "desktop/core_window.h" #include "desktop/textinput.h" #include "utils/errors.h" diff --git a/desktop/system_colour.c b/desktop/system_colour.c index 4ef170981..178c03536 100644 --- a/desktop/system_colour.c +++ b/desktop/system_colour.c @@ -21,45 +21,47 @@ * */ +#include <string.h> + +#include "utils/config.h" #include "utils/utils.h" #include "utils/log.h" #include "css/utils.h" -#include "desktop/gui.h" +#include "desktop/system_colour.h" #include "utils/nsoption.h" - #define colour_list_len ((NSOPTION_SYS_COLOUR_END - NSOPTION_SYS_COLOUR_START) + 1) static lwc_string *colour_list[colour_list_len]; -static lwc_string **gui_system_colour_pw = NULL; +static lwc_string **ns_system_colour_pw = NULL; -bool gui_system_colour_init(void) +nserror ns_system_colour_init(void) { unsigned int ccount; - if (gui_system_colour_pw != NULL) - return false; + if (ns_system_colour_pw != NULL) + return NSERROR_INIT_FAILED; /* Intern colour strings */ for (ccount = 0; ccount < colour_list_len; ccount++) { struct nsoption_s *opt; opt = &nsoptions[ccount + NSOPTION_SYS_COLOUR_START]; - if (lwc_intern_string(opt->key + SLEN("sys_colour_"), - opt->key_len - SLEN("sys_colour_"), + if (lwc_intern_string(opt->key + SLEN("sys_colour_"), + opt->key_len - SLEN("sys_colour_"), &(colour_list[ccount])) != lwc_error_ok) { - return false; + return NSERROR_NOMEM; } } - gui_system_colour_pw = colour_list; - - return true; + ns_system_colour_pw = colour_list; + + return NSERROR_OK; } -void gui_system_colour_finalize(void) +void ns_system_colour_finalize(void) { unsigned int ccount; @@ -68,7 +70,7 @@ void gui_system_colour_finalize(void) } } -colour gui_system_colour_char(const char *name) +colour ns_system_colour_char(const char *name) { colour ret = 0; unsigned int ccount; @@ -83,19 +85,19 @@ colour gui_system_colour_char(const char *name) return ret; } -css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour) +css_error ns_system_colour(void *pw, lwc_string *name, css_color *colour) { unsigned int ccount; bool match; for (ccount = 0; ccount < colour_list_len; ccount++) { - if (lwc_string_caseless_isequal(name, + if (lwc_string_caseless_isequal(name, colour_list[ccount], &match) == lwc_error_ok && match) { *colour = ns_color_to_nscss(nsoptions[ccount + NSOPTION_SYS_COLOUR_START].value.c); return CSS_OK; } - } + } return CSS_INVALID; } diff --git a/desktop/401login.h b/desktop/system_colour.h index 1c8140bae..b5d4baad4 100644 --- a/desktop/401login.h +++ b/desktop/system_colour.h @@ -1,5 +1,5 @@ /* - * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk> + * Copyright 2014 vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,16 +16,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NETSURF_DESKTOP_401LOGIN_H -#define NETSURF_DESKTOP_401LOGIN_H +/** \file + * Interface to system colour values. + */ + +#ifndef _NETSURF_DESKTOP_SYSTEM_COLOUR_H_ +#define _NETSURF_DESKTOP_SYSTEM_COLOUR_H_ -#include <stdbool.h> +#include <libcss/libcss.h> -#include "utils/config.h" -#include "utils/nsurl.h" #include "utils/errors.h" +#include "desktop/plot_style.h" + +/** css callback to obtain named system colours. */ +css_error ns_system_colour(void *pw, lwc_string *name, css_color *color); + +/** Obtain a named system colour from a frontend. */ +colour ns_system_colour_char(const char *name); -void gui_401login_open(nsurl *url, const char *realm, - nserror (*cb)(bool proceed, void *pw), void *cbpw); +nserror ns_system_colour_init(void); +void ns_system_colour_finalize(void); #endif diff --git a/desktop/textarea.c b/desktop/textarea.c index bfa07ad4f..2ba09824d 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -24,11 +24,13 @@ #include <stdint.h> #include <string.h> #include "css/utils.h" + #include "desktop/mouse.h" #include "desktop/textarea.h" #include "desktop/textinput.h" #include "desktop/plotters.h" #include "desktop/scrollbar.h" +#include "desktop/gui_factory.h" #include "render/font.h" #include "utils/log.h" #include "utils/utf8.h" @@ -160,6 +162,7 @@ static void textarea_normalise_text(struct textarea *ta, unsigned int b_start, unsigned int b_len) { bool multi = (ta->flags & TEXTAREA_MULTILINE) ? true : false; + struct textarea_msg msg; unsigned int index; /* Remove CR characters. If it's a CRLF pair delete the CR, or replace @@ -187,6 +190,25 @@ static void textarea_normalise_text(struct textarea *ta, ta->text.data[b_start + index] = ' '; } + /* Build text modified message */ + msg.ta = ta; + msg.type = TEXTAREA_MSG_TEXT_MODIFIED; + msg.data.modified.text = ta->text.data; + msg.data.modified.len = ta->text.len; + + /* Pass message to client */ + ta->callback(ta->data, &msg); +} + + +/** + * Reset the selection (no redraw) + * + * \param ta Text area + */ +static inline void textarea_reset_selection(struct textarea *ta) +{ + ta->sel_start = ta->sel_end = -1; } @@ -1408,7 +1430,7 @@ static bool textarea_replace_text_internal(struct textarea *ta, size_t b_start, /* Place CUTs on clipboard */ if (add_to_clipboard) { - gui_set_clipboard(ta->show->data + b_start, b_end - b_start, + guit->clipboard->set(ta->show->data + b_start, b_end - b_start, NULL, 0); } @@ -1758,13 +1780,14 @@ static void textarea_setup_text_offsets(struct textarea *ta) if (ta->flags & TEXTAREA_MULTILINE) { /* Multiline textarea */ text_y_offset += ta->pad_top; - text_y_offset_baseline += (ta->line_height * 3 + 2) / 4 + - ta->pad_top; + text_y_offset_baseline += + (ta->line_height * 3 + 2) / 4 + ta->pad_top; } else { /* Single line text area; text is vertically centered */ int vis_height = ta->vis_height - 2 * ta->border_width; text_y_offset += (vis_height - ta->line_height + 1) / 2; - text_y_offset_baseline += (vis_height * 3 + 2) / 4; + text_y_offset_baseline += + (2 * vis_height + ta->line_height + 2) / 4; } ta->text_y_offset = text_y_offset; @@ -1872,9 +1895,9 @@ struct textarea *textarea_create(const textarea_flags flags, ret->show = &ret->text; } - ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.3), - FMUL(nscss_screen_dpi, INTTOFIX((setup->text.size))))), - FONT_SIZE_SCALE * F_72)); + ret->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL( + nscss_screen_dpi, FDIV(INTTOFIX(setup->text.size), + INTTOFIX(FONT_SIZE_SCALE))), F_72))); ret->caret_pos.line = ret->caret_pos.byte_off = -1; ret->caret_x = 0; @@ -2067,10 +2090,17 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, r = *clip; - if (r.x1 < x || r.x0 > x + ta->vis_width || r.y1 < y || - r.y0 > y + ta->vis_height) - /* Textarea outside the clipping rectangle */ + /* Nothing to render if textarea is outside clip rectangle */ + if (r.x1 < x || r.y1 < y) return; + if (scale == 1.0) { + if (r.x0 > x + ta->vis_width || r.y0 > y + ta->vis_height) + return; + } else { + if (r.x0 > x + ta->vis_width * scale || + r.y0 > y + ta->vis_height * scale) + return; + } if (ta->lines == NULL) /* Nothing to redraw */ @@ -2146,7 +2176,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, scale) r.y1 = y + (ta->vis_height - ta->border_width - (ta->bar_x != NULL ? SCROLLBAR_WIDTH : - 0) * scale); + 0)) * scale; } if (line0 > 0) @@ -2253,6 +2283,8 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, &right); } else { right = ta->lines[line].width; + if (scale != 1.0) + right *= scale; } right += x + ta->border_width + ta->pad_left - ta->scroll_x; @@ -2380,8 +2412,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) length, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { if (!textarea_replace_text(ta, caret, caret, utf8, length, false, &byte_delta, &r)) @@ -2411,8 +2444,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) "", 0, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else if (caret > 0) { b_off = utf8_prev(ta->show->data, caret); if (!textarea_replace_text(ta, b_off, caret, @@ -2431,8 +2465,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) "", 0, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else if (caret < ta->show->len - 1) { b_off = utf8_next(ta->show->data, ta->show->len - 1, caret); @@ -2456,8 +2491,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { if (!textarea_replace_text(ta, caret, caret, "\n", 1, false, @@ -2475,7 +2511,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) if (readonly) break; - gui_get_clipboard(&clipboard, &clipboard_length); + guit->clipboard->get(&clipboard, &clipboard_length); if (clipboard == NULL) return false; @@ -2486,8 +2522,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { if (!textarea_replace_text(ta, caret, caret, @@ -2510,9 +2547,10 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) "", 0, true, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; caret += byte_delta; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } break; case KEY_ESCAPE: @@ -2684,8 +2722,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) ta->sel_start, ta->sel_end, "", 0, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { if (ta->lines[line].b_length != 0) { /* Delete line */ @@ -2716,8 +2755,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) ta->sel_start, ta->sel_end, "", 0, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { b_len = ta->lines[line].b_length; b_off = ta->lines[line].b_start + b_len; @@ -2737,8 +2777,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) ta->sel_start, ta->sel_end, "", 0, false, &byte_delta, &r)) return false; + redraw = true; caret = ta->sel_end; - textarea_clear_selection(ta); + textarea_reset_selection(ta); } else { if (!textarea_replace_text(ta, caret - ta->caret_pos.byte_off, @@ -3023,7 +3064,7 @@ bool textarea_clear_selection(struct textarea *ta) break; /* Clear selection and redraw */ - ta->sel_start = ta->sel_end = -1; + textarea_reset_selection(ta); msg.ta = ta; msg.type = TEXTAREA_MSG_REDRAW_REQUEST; diff --git a/desktop/textarea.h b/desktop/textarea.h index 016f15a10..1c24dd1cc 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -51,7 +51,8 @@ typedef enum { TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */ TEXTAREA_MSG_SELECTION_REPORT, /**< Textarea text selection presence */ TEXTAREA_MSG_REDRAW_REQUEST, /**< Textarea redraw request */ - TEXTAREA_MSG_CARET_UPDATE /**< Textarea caret */ + TEXTAREA_MSG_CARET_UPDATE, /**< Textarea caret */ + TEXTAREA_MSG_TEXT_MODIFIED /**< Textarea text modified */ } textarea_msg_type; struct textarea_msg { @@ -77,6 +78,10 @@ struct textarea_msg { struct rect *clip; /**< Carret clip rect */ } pos; /**< With _CARET_SET_POS */ } caret; /**< With _CARET_UPDATE */ + struct { + const char *text; /**< UTF8 text */ + unsigned int len; /**< Byte length of text */ + } modified; /**< With _TEXT_MODIFIED */ } data; /**< Depends on msg type */ }; diff --git a/desktop/textinput.c b/desktop/textinput.c index e804829fa..fd6ae9ff1 100644 --- a/desktop/textinput.c +++ b/desktop/textinput.c @@ -30,7 +30,7 @@ #include <dom/dom.h> #include "desktop/browser_private.h" -#include "desktop/gui.h" +#include "desktop/gui_factory.h" #include "desktop/mouse.h" #include "desktop/scrollbar.h" #include "desktop/selection.h" @@ -85,7 +85,7 @@ void browser_window_place_caret(struct browser_window *bw, int x, int y, /* TODO: intersect with bw viewport */ - gui_window_place_caret(root_bw->window, x, y, height * bw->scale, crp); + guit->window->place_caret(root_bw->window, x, y, height * bw->scale, crp); /* Set focus browser window */ root_bw->focus = bw; @@ -110,8 +110,9 @@ void browser_window_remove_caret(struct browser_window *bw, bool only_hide) else root_bw->can_edit = false; - if (root_bw->window) - gui_window_remove_caret(root_bw->window); + if (root_bw->window) { + guit->window->remove_caret(root_bw->window); + } } diff --git a/desktop/tree.c b/desktop/tree.c index 6097c22a6..c29afa761 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -36,7 +36,6 @@ #include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" -#include "utils/url.h" struct tree { unsigned int flags; /* Tree flags */ @@ -133,6 +132,10 @@ static bool treeview_test_init(struct tree *tree) switch (tree->flags) { case TREE_COOKIES: + assert(ssl_current_session == NULL && + "Call sslcert_viewer_init directly, " + "this compat. layer can't cope with simultanious " + "sslcert viewers"); err = cookie_manager_init(&cw_t, (struct core_window *)tree); if (err != NSERROR_OK) warn_user("Couldn't init new cookie manager.", 0); @@ -180,7 +183,10 @@ static bool treeview_test_fini(struct tree *tree) warn_user("Couldn't finalise hotlist.", 0); break; case TREE_SSLCERT: + assert(ssl_current_session != NULL && + "Can't use sslcert window after sslcert_viewer_fini()"); err = sslcert_viewer_fini(ssl_current_session); + ssl_current_session = NULL; if (err != NSERROR_OK) warn_user("Couldn't finalise sslcert viewer.", 0); break; @@ -206,7 +212,9 @@ static bool treeview_test_redraw(struct tree *tree, int x, int y, switch (tree->flags) { case TREE_SSLCERT: - sslcert_viewer_redraw(ssl_current_session, x, y, &clip, ctx); + if (ssl_current_session != NULL) { + sslcert_viewer_redraw(ssl_current_session, x, y, &clip, ctx); + } return true; case TREE_COOKIES: cookie_manager_redraw(x, y, &clip, ctx); @@ -227,6 +235,8 @@ static bool treeview_test_mouse_action(struct tree *tree, { switch (tree->flags) { case TREE_SSLCERT: + assert(ssl_current_session != NULL && + "Can't use sslcert window after sslcert_viewer_fini()"); sslcert_viewer_mouse_action(ssl_current_session, mouse, x, y); return true; case TREE_COOKIES: @@ -247,6 +257,8 @@ static bool treeview_test_keypress(struct tree *tree, uint32_t key) { switch (tree->flags) { case TREE_SSLCERT: + assert(ssl_current_session != NULL && + "Can't use sslcert window after sslcert_viewer_fini()"); sslcert_viewer_keypress(ssl_current_session, key); return true; case TREE_COOKIES: diff --git a/desktop/tree.h b/desktop/tree.h index db164c013..b4e0f66b7 100644 --- a/desktop/tree.h +++ b/desktop/tree.h @@ -27,10 +27,18 @@ #include <stdbool.h> #include <stdint.h> -#include "desktop/browser.h" +#include "desktop/mouse.h" struct sslcert_session_data; +struct tree; +struct redraw_context; +/** + * Current ssl session data for treeview + * + * @todo FIXME global certificate treeview state must go away, this is + * just wrong. + */ extern struct sslcert_session_data *ssl_current_session; extern const char *tree_hotlist_path; @@ -42,9 +50,6 @@ enum tree_flags { TREE_HOTLIST }; - -struct tree; - typedef enum { TREE_NO_DRAG = 0, TREE_SELECT_DRAG, diff --git a/desktop/treeview.c b/desktop/treeview.c index a137c46c5..484d279cf 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -20,15 +20,17 @@ * Treeview handling (implementation). */ +#include "utils/log.h" #include "css/utils.h" -#include "desktop/gui.h" +#include "image/bitmap.h" +#include "render/font.h" +#include "content/hlcache.h" + +#include "desktop/system_colour.h" #include "desktop/knockout.h" #include "desktop/plotters.h" #include "desktop/textarea.h" #include "desktop/treeview.h" -#include "image/bitmap.h" -#include "render/font.h" -#include "utils/log.h" /* TODO: get rid of REDRAW_MAX -- need to be able to know window size */ #define REDRAW_MAX 8000 @@ -64,10 +66,10 @@ struct treeview_field { }; enum treeview_node_flags { - TREE_NODE_NONE = 0, /**< No node flags set */ - TREE_NODE_EXPANDED = (1 << 0), /**< Whether node is expanded */ - TREE_NODE_SELECTED = (1 << 1), /**< Whether node is selected */ - TREE_NODE_SPECIAL = (1 << 2) /**< Render as special node */ + TV_NFLAGS_NONE = 0, /**< No node flags set */ + TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */ + TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */ + TV_NFLAGS_SPECIAL = (1 << 2) /**< Render as special node */ }; enum treeview_target_pos { @@ -219,7 +221,7 @@ static inline treeview_node * treeview_node_next(treeview_node *node, bool full) { assert(node != NULL); - if ((full || (node->flags & TREE_NODE_EXPANDED)) && + if ((full || (node->flags & TV_NFLAGS_EXPANDED)) && node->children != NULL) { /* Next node is child */ node = node->children; @@ -330,7 +332,7 @@ static nserror treeview_walk_internal(treeview_node *root, bool full, parent = node->parent; next_sibling = node->next_sib; child = (!skip_children && - (full || (node->flags & TREE_NODE_EXPANDED))) ? + (full || (node->flags & TV_NFLAGS_EXPANDED))) ? node->children : NULL; while (node != NULL) { @@ -387,7 +389,7 @@ static nserror treeview_walk_internal(treeview_node *root, bool full, parent = node->parent; next_sibling = node->next_sib; - child = (full || (node->flags & TREE_NODE_EXPANDED)) ? + child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ? node->children : NULL; if (callback_fwd != NULL) { @@ -423,7 +425,7 @@ static nserror treeview_create_node_root(treeview_node **root) return NSERROR_NOMEM; } - n->flags = TREE_NODE_EXPANDED; + n->flags = TV_NFLAGS_EXPANDED; n->type = TREE_NODE_ROOT; n->height = 0; @@ -506,7 +508,7 @@ static inline void treeview_insert_node(treeview_node *a, treeview_set_inset_from_parent, NULL); } - if (a->parent->flags & TREE_NODE_EXPANDED) { + if (a->parent->flags & TV_NFLAGS_EXPANDED) { int height = a->height; /* Parent is expanded, so inserted node will be visible and * affect layout */ @@ -550,7 +552,7 @@ nserror treeview_create_node_folder(treeview *tree, } n->flags = (flags & TREE_OPTION_SPECIAL_DIR) ? - TREE_NODE_SPECIAL : TREE_NODE_NONE; + TV_NFLAGS_SPECIAL : TV_NFLAGS_NONE; n->type = TREE_NODE_FOLDER; n->height = tree_g.line_height; @@ -568,7 +570,7 @@ nserror treeview_create_node_folder(treeview *tree, treeview_insert_node(n, relation, rel); - if (n->parent->flags & TREE_NODE_EXPANDED) { + if (n->parent->flags & TV_NFLAGS_EXPANDED) { /* Inform front end of change in dimensions */ if (!(flags & TREE_OPTION_SUPPRESS_RESIZE)) tree->cw_t->update_size(tree->cw_h, -1, @@ -613,7 +615,7 @@ nserror treeview_update_node_folder(treeview *tree, folder->text.len = field->value_len; folder->text.width = 0; - if (folder->parent->flags & TREE_NODE_EXPANDED) { + if (folder->parent->flags & TV_NFLAGS_EXPANDED) { /* Text will be seen, get its width */ nsfont.font_width(&plot_style_odd.text, folder->text.data, @@ -625,7 +627,7 @@ nserror treeview_update_node_folder(treeview *tree, } /* Redraw */ - if (folder->parent->flags & TREE_NODE_EXPANDED) { + if (folder->parent->flags & TV_NFLAGS_EXPANDED) { struct rect r; r.x0 = 0; r.y0 = treeview_node_y(tree, folder); @@ -663,7 +665,7 @@ nserror treeview_update_node_entry(treeview *tree, entry->text.len = fields[0].value_len; entry->text.width = 0; - if (entry->parent->flags & TREE_NODE_EXPANDED) { + if (entry->parent->flags & TV_NFLAGS_EXPANDED) { /* Text will be seen, get its width */ nsfont.font_width(&plot_style_odd.text, entry->text.data, @@ -683,7 +685,7 @@ nserror treeview_update_node_entry(treeview *tree, e->fields[i - 1].value.data = fields[i].value; e->fields[i - 1].value.len = fields[i].value_len; - if (entry->flags & TREE_NODE_EXPANDED) { + if (entry->flags & TV_NFLAGS_EXPANDED) { /* Text will be seen, get its width */ nsfont.font_width(&plot_style_odd.text, e->fields[i - 1].value.data, @@ -696,7 +698,7 @@ nserror treeview_update_node_entry(treeview *tree, } /* Redraw */ - if (entry->parent->flags & TREE_NODE_EXPANDED) { + if (entry->parent->flags & TV_NFLAGS_EXPANDED) { struct rect r; r.x0 = 0; r.y0 = treeview_node_y(tree, entry); @@ -740,7 +742,7 @@ nserror treeview_create_node_entry(treeview *tree, n = (treeview_node *) e; - n->flags = TREE_NODE_NONE; + n->flags = TV_NFLAGS_NONE; n->type = TREE_NODE_ENTRY; n->height = tree_g.line_height; @@ -774,7 +776,7 @@ nserror treeview_create_node_entry(treeview *tree, treeview_insert_node(n, relation, rel); - if (n->parent->flags & TREE_NODE_EXPANDED) { + if (n->parent->flags & TV_NFLAGS_EXPANDED) { /* Inform front end of change in dimensions */ if (!(flags & TREE_OPTION_SUPPRESS_RESIZE)) tree->cw_t->update_size(tree->cw_h, -1, @@ -874,7 +876,7 @@ static inline bool treeview_unlink_node(treeview_node *n) } /* Reduce ancestor heights */ - if (n->parent != NULL && n->parent->flags & TREE_NODE_EXPANDED) { + if (n->parent != NULL && n->parent->flags & TV_NFLAGS_EXPANDED) { return true; } @@ -1067,13 +1069,13 @@ static nserror treeview_delete_node_internal(treeview *tree, treeview_node *n, n = p; /* Reduce ancestor heights */ - while (n != NULL && n->flags & TREE_NODE_EXPANDED) { + while (n != NULL && n->flags & TV_NFLAGS_EXPANDED) { n->height -= nd.h_reduction; n = n->parent; } /* Inform front end of change in dimensions */ - if (tree->root != NULL && p != NULL && p->flags & TREE_NODE_EXPANDED && + if (tree->root != NULL && p != NULL && p->flags & TV_NFLAGS_EXPANDED && nd.h_reduction > 0 && !(flags & TREE_OPTION_SUPPRESS_RESIZE)) { tree->cw_t->update_size(tree->cw_h, -1, @@ -1112,7 +1114,7 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction) node = tree->root; parent = node->parent; next_sibling = node->next_sib; - child = (node->flags & TREE_NODE_EXPANDED) ? node->children : NULL; + child = (node->flags & TV_NFLAGS_EXPANDED) ? node->children : NULL; while (node != NULL) { @@ -1139,7 +1141,7 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction) /* Reduce ancestor heights */ while (p != NULL && p->flags & - TREE_NODE_EXPANDED) { + TV_NFLAGS_EXPANDED) { p->height -= nd.h_reduction; p = p->parent; } @@ -1165,7 +1167,7 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction) /* Reduce ancestor heights */ while (p != NULL && - p->flags & TREE_NODE_EXPANDED) { + p->flags & TV_NFLAGS_EXPANDED) { p->height -= nd.h_reduction; p = p->parent; } @@ -1179,7 +1181,7 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction) parent = node->parent; next_sibling = node->next_sib; - child = (node->flags & TREE_NODE_EXPANDED) ? + child = (node->flags & TV_NFLAGS_EXPANDED) ? node->children : NULL; } @@ -1199,7 +1201,7 @@ nserror treeview_delete_node(treeview *tree, treeview_node *n, assert(n != NULL); assert(n->parent != NULL); - visible = n->parent->flags & TREE_NODE_EXPANDED; + visible = n->parent->flags & TV_NFLAGS_EXPANDED; r.y0 = treeview_node_y(tree, n); r.y1 = tree->root->height; @@ -1365,7 +1367,7 @@ static nserror treeview_node_expand_internal(treeview *tree, assert(tree != NULL); assert(node != NULL); - if (node->flags & TREE_NODE_EXPANDED) { + if (node->flags & TV_NFLAGS_EXPANDED) { /* What madness is this? */ LOG(("Tried to expand an expanded node.")); return NSERROR_OK; @@ -1380,7 +1382,7 @@ static nserror treeview_node_expand_internal(treeview *tree, } do { - assert((child->flags & TREE_NODE_EXPANDED) == false); + assert((child->flags & TV_NFLAGS_EXPANDED) == false); if (child->text.width == 0) { nsfont.font_width(&plot_style_odd.text, child->text.data, @@ -1416,12 +1418,14 @@ static nserror treeview_node_expand_internal(treeview *tree, break; case TREE_NODE_ROOT: + case TREE_NODE_NONE: assert(node->type != TREE_NODE_ROOT); + assert(node->type != TREE_NODE_NONE); break; } /* Update the node */ - node->flags |= TREE_NODE_EXPANDED; + node->flags |= TV_NFLAGS_EXPANDED; /* And parent's heights */ do { @@ -1473,15 +1477,15 @@ static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end) assert(n != NULL); assert(n->type != TREE_NODE_ROOT); - n->flags &= ~TREE_NODE_SELECTED; + n->flags &= ~TV_NFLAGS_SELECTED; - if ((n->flags & TREE_NODE_EXPANDED) == false || + if ((n->flags & TV_NFLAGS_EXPANDED) == false || (n->type == TREE_NODE_FOLDER && data->only_entries)) { /* Nothing to do. */ return NSERROR_OK; } - n->flags ^= TREE_NODE_EXPANDED; + n->flags ^= TV_NFLAGS_EXPANDED; h_reduction = n->height - tree_g.line_height; assert(h_reduction >= 0); @@ -1507,14 +1511,14 @@ static nserror treeview_node_contract_internal(treeview *tree, bool selected; assert(node != NULL); - if ((node->flags & TREE_NODE_EXPANDED) == false) { + if ((node->flags & TV_NFLAGS_EXPANDED) == false) { /* What madness is this? */ LOG(("Tried to contract a contracted node.")); return NSERROR_OK; } data.only_entries = false; - selected = node->flags & TREE_NODE_SELECTED; + selected = node->flags & TV_NFLAGS_SELECTED; /* Contract children. */ treeview_walk_internal(node, false, treeview_node_contract_cb, @@ -1524,7 +1528,7 @@ static nserror treeview_node_contract_internal(treeview *tree, treeview_node_contract_cb(node, &data, false); if (selected) - node->flags |= TREE_NODE_SELECTED; + node->flags |= TV_NFLAGS_SELECTED; /* Inform front end of change in dimensions */ tree->cw_t->update_size(tree->cw_h, -1, tree->root->height); @@ -1576,11 +1580,11 @@ nserror treeview_contract(treeview *tree, bool all) data.only_entries = !all; for (n = tree->root->children; n != NULL; n = n->next_sib) { - if ((n->flags & TREE_NODE_EXPANDED) == false) { + if ((n->flags & TV_NFLAGS_EXPANDED) == false) { continue; } - selected = n->flags & TREE_NODE_SELECTED; + selected = n->flags & TV_NFLAGS_SELECTED; /* Contract children. */ treeview_walk_internal(n, false, @@ -1590,7 +1594,7 @@ nserror treeview_contract(treeview *tree, bool all) treeview_node_contract_cb(n, &data, false); if (selected) - n->flags |= TREE_NODE_SELECTED; + n->flags |= TV_NFLAGS_SELECTED; } /* Inform front end of change in dimensions */ @@ -1617,7 +1621,7 @@ static nserror treeview_expand_cb(treeview_node *n, void *ctx, assert(n != NULL); assert(n->type != TREE_NODE_ROOT); - if (n->flags & TREE_NODE_EXPANDED || + if (n->flags & TV_NFLAGS_EXPANDED || (data->only_folders && n->type != TREE_NODE_FOLDER)) { /* Nothing to do. */ return NSERROR_OK; @@ -1683,7 +1687,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, assert(tree != NULL); assert(tree->root != NULL); - assert(tree->root->flags & TREE_NODE_EXPANDED); + assert(tree->root->flags & TV_NFLAGS_EXPANDED); if (tree->drag.start.y > tree->drag.prev.y) { sel_min = tree->drag.prev.y; @@ -1716,7 +1720,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, while (node != NULL) { int i; - next = (node->flags & TREE_NODE_EXPANDED) ? + next = (node->flags & TV_NFLAGS_EXPANDED) ? node->children : NULL; if (next != NULL) { @@ -1762,20 +1766,20 @@ void treeview_redraw(treeview *tree, const int x, const int y, } else { invert_selection = false; } - if ((node->flags & TREE_NODE_SELECTED && !invert_selection) || - (!(node->flags & TREE_NODE_SELECTED) && + if ((node->flags & TV_NFLAGS_SELECTED && !invert_selection) || + (!(node->flags & TV_NFLAGS_SELECTED) && invert_selection)) { bg_style = &style->sbg; text_style = &style->stext; infotext_style = &style->sitext; - furniture = (node->flags & TREE_NODE_EXPANDED) ? + furniture = (node->flags & TV_NFLAGS_EXPANDED) ? style->furn[TREE_FURN_CONTRACT].sel : style->furn[TREE_FURN_EXPAND].sel; } else { bg_style = &style->bg; text_style = &style->text; infotext_style = &style->itext; - furniture = (node->flags & TREE_NODE_EXPANDED) ? + furniture = (node->flags & TV_NFLAGS_EXPANDED) ? style->furn[TREE_FURN_CONTRACT].bmp : style->furn[TREE_FURN_EXPAND].bmp; } @@ -1795,7 +1799,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, /* Render icon */ if (node->type == TREE_NODE_ENTRY) res = TREE_RES_CONTENT; - else if (node->flags & TREE_NODE_SPECIAL) + else if (node->flags & TV_NFLAGS_SPECIAL) res = TREE_RES_FOLDER_SPECIAL; else res = TREE_RES_FOLDER; @@ -1827,7 +1831,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, if (node->type != TREE_NODE_ENTRY || - !(node->flags & TREE_NODE_EXPANDED)) + !(node->flags & TV_NFLAGS_EXPANDED)) /* Done everything for this node */ continue; @@ -1949,7 +1953,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, switch (sw->purpose) { case TREEVIEW_WALK_HAS_SELECTION: - if (n->flags & TREE_NODE_SELECTED) { + if (n->flags & TV_NFLAGS_SELECTED) { sw->data.has_selection = true; *end = true; /* Can abort tree walk */ return NSERROR_OK; @@ -1957,7 +1961,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, break; case TREEVIEW_WALK_GET_FIRST_SELECTED: - if (n->flags & TREE_NODE_SELECTED) { + if (n->flags & TV_NFLAGS_SELECTED) { sw->data.first.n = n; *end = true; /* Can abort tree walk */ return NSERROR_OK; @@ -1965,7 +1969,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, break; case TREEVIEW_WALK_DELETE_SELECTION: - if (n->flags & TREE_NODE_SELECTED) { + if (n->flags & TV_NFLAGS_SELECTED) { err = treeview_delete_node_internal(sw->tree, n, true, TREE_OPTION_NONE); if (err != NSERROR_OK) { @@ -1978,23 +1982,23 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, case TREEVIEW_WALK_PROPAGATE_SELECTION: if (n->parent != NULL && - n->parent->flags & TREE_NODE_SELECTED && - !(n->flags & TREE_NODE_SELECTED)) { - n->flags ^= TREE_NODE_SELECTED; + n->parent->flags & TV_NFLAGS_SELECTED && + !(n->flags & TV_NFLAGS_SELECTED)) { + n->flags ^= TV_NFLAGS_SELECTED; changed = true; } break; case TREEVIEW_WALK_CLEAR_SELECTION: - if (n->flags & TREE_NODE_SELECTED) { - n->flags ^= TREE_NODE_SELECTED; + if (n->flags & TV_NFLAGS_SELECTED) { + n->flags ^= TV_NFLAGS_SELECTED; changed = true; } break; case TREEVIEW_WALK_SELECT_ALL: - if (!(n->flags & TREE_NODE_SELECTED)) { - n->flags ^= TREE_NODE_SELECTED; + if (!(n->flags & TV_NFLAGS_SELECTED)) { + n->flags ^= TV_NFLAGS_SELECTED; changed = true; } break; @@ -2003,12 +2007,12 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, if (sw->current_y >= sw->data.drag.sel_min && sw->current_y - height < sw->data.drag.sel_max) { - n->flags ^= TREE_NODE_SELECTED; + n->flags ^= TV_NFLAGS_SELECTED; } return NSERROR_OK; case TREEVIEW_WALK_YANK_SELECTION: - if (n->flags & TREE_NODE_SELECTED) { + if (n->flags & TV_NFLAGS_SELECTED) { treeview_node *p = n->parent; int h = 0; @@ -2016,7 +2020,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n, h = n->height; /* Reduce ancestor heights */ - while (p != NULL && p->flags & TREE_NODE_EXPANDED) { + while (p != NULL && p->flags & TV_NFLAGS_EXPANDED) { p->height -= h; p = p->parent; } @@ -2089,7 +2093,8 @@ static treeview_node * treeview_get_first_selected(treeview *tree) /* Exported interface, documented in treeview.h */ -void treeview_get_selection(treeview *tree, void **node_data) +enum treeview_node_type treeview_get_selection(treeview *tree, + void **node_data) { treeview_node *n; @@ -2097,7 +2102,13 @@ void treeview_get_selection(treeview *tree, void **node_data) n = treeview_get_first_selected(tree); - *node_data = n->client_data; + if (n != NULL && n->type & (TREE_NODE_ENTRY | TREE_NODE_FOLDER)) { + *node_data = n->client_data; + return n->type; + } + + *node_data = NULL; + return TREE_NODE_NONE; } @@ -2332,7 +2343,7 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect) } /* The node that we're moving selection to can't itself be selected */ - assert(!(relation->flags & TREE_NODE_SELECTED)); + assert(!(relation->flags & TV_NFLAGS_SELECTED)); /* Move all selected nodes from treeview to tree->move.root */ treeview_move_yank_selection(tree); @@ -2341,10 +2352,10 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect) for (node = tree->move.root; node != NULL; node = next) { next = node->next_sib; - if (!(parent->flags & TREE_NODE_EXPANDED)) { - if (node->flags & TREE_NODE_EXPANDED) + if (!(parent->flags & TV_NFLAGS_EXPANDED)) { + if (node->flags & TV_NFLAGS_EXPANDED) treeview_node_contract_internal(tree, node); - node->flags &= ~TREE_NODE_SELECTED; + node->flags &= ~TV_NFLAGS_SELECTED; } treeview_insert_node(node, relation, relationship); @@ -2378,7 +2389,7 @@ static nserror treeview_node_launch_walk_bwd_cb(treeview_node *n, void *ctx, { struct treeview_launch_walk_data *lw = ctx; - if (n->type == TREE_NODE_FOLDER && n->flags == TREE_NODE_SELECTED) { + if (n->type == TREE_NODE_FOLDER && n->flags == TV_NFLAGS_SELECTED) { lw->selected_depth--; } @@ -2390,11 +2401,11 @@ static nserror treeview_node_launch_walk_fwd_cb(treeview_node *n, void *ctx, { struct treeview_launch_walk_data *lw = ctx; - if (n->type == TREE_NODE_FOLDER && n->flags & TREE_NODE_SELECTED) { + if (n->type == TREE_NODE_FOLDER && n->flags & TV_NFLAGS_SELECTED) { lw->selected_depth++; } else if (n->type == TREE_NODE_ENTRY && - (n->flags & TREE_NODE_SELECTED || + (n->flags & TV_NFLAGS_SELECTED || lw->selected_depth > 0)) { struct treeview_node_msg msg; msg.msg = TREE_MSG_NODE_LAUNCH; @@ -2491,7 +2502,7 @@ static nserror treeview_node_nav_cb(treeview_node *node, void *ctx, if (node == ns->tree->root) return NSERROR_OK; - if (node->flags & TREE_NODE_SELECTED) { + if (node->flags & TV_NFLAGS_SELECTED) { ns->n_selected++; if (ns->curr == NULL) { ns->curr = node; @@ -2554,51 +2565,51 @@ static bool treeview_keyboard_navigation(treeview *tree, uint32_t key, ns.curr->parent != NULL && ns.curr->parent->type != TREE_NODE_ROOT) { /* Step to parent */ - ns.curr->parent->flags |= TREE_NODE_SELECTED; + ns.curr->parent->flags |= TV_NFLAGS_SELECTED; } else if (ns.curr != NULL && tree->root->children != NULL) { /* Select first node in tree */ - tree->root->children->flags |= TREE_NODE_SELECTED; + tree->root->children->flags |= TV_NFLAGS_SELECTED; } break; case KEY_RIGHT: if (ns.curr != NULL) { - if (!(ns.curr->flags & TREE_NODE_EXPANDED)) { + if (!(ns.curr->flags & TV_NFLAGS_EXPANDED)) { /* Toggle node to expanded */ treeview_node_expand_internal(tree, ns.curr); if (ns.curr->children != NULL) { /* Step to first child */ ns.curr->children->flags |= - TREE_NODE_SELECTED; + TV_NFLAGS_SELECTED; } else { /* Retain current node selection */ - ns.curr->flags |= TREE_NODE_SELECTED; + ns.curr->flags |= TV_NFLAGS_SELECTED; } } else { /* Toggle node to contracted */ treeview_node_contract_internal(tree, ns.curr); /* Retain current node selection */ - ns.curr->flags |= TREE_NODE_SELECTED; + ns.curr->flags |= TV_NFLAGS_SELECTED; } } else if (ns.curr != NULL) { /* Retain current node selection */ - ns.curr->flags |= TREE_NODE_SELECTED; + ns.curr->flags |= TV_NFLAGS_SELECTED; } break; case KEY_UP: if (ns.prev != NULL) { /* Step to previous node */ - ns.prev->flags |= TREE_NODE_SELECTED; + ns.prev->flags |= TV_NFLAGS_SELECTED; } break; case KEY_DOWN: if (ns.next != NULL) { /* Step to next node */ - ns.next->flags |= TREE_NODE_SELECTED; + ns.next->flags |= TV_NFLAGS_SELECTED; } break; @@ -2720,16 +2731,16 @@ static bool treeview_set_move_indicator(treeview *tree, bool need_redraw, assert(tree->root->children != NULL); assert(target != NULL); - if (target->flags & TREE_NODE_SELECTED) { + if (target->flags & TV_NFLAGS_SELECTED) { /* Find top selected ancestor */ while (target->parent && - target->parent->flags & TREE_NODE_SELECTED) { + target->parent->flags & TV_NFLAGS_SELECTED) { target = target->parent; } /* Find top ajdacent selected sibling */ while (target->prev_sib && - target->prev_sib->flags & TREE_NODE_SELECTED) { + target->prev_sib->flags & TV_NFLAGS_SELECTED) { target = target->prev_sib; } target_pos = TV_TARGET_ABOVE; @@ -2739,7 +2750,7 @@ static bool treeview_set_move_indicator(treeview *tree, bool need_redraw, if (mouse_pos <= node_height / 4) { target_pos = TV_TARGET_ABOVE; } else if (mouse_pos <= (3 * node_height) / 4 || - target->flags & TREE_NODE_EXPANDED) { + target->flags & TV_NFLAGS_EXPANDED) { target_pos = TV_TARGET_INSIDE; } else { target_pos = TV_TARGET_BELOW; @@ -3127,7 +3138,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx, /* Record what position / part a drag started on */ if (ma->mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) && ma->tree->drag.type == TV_DRAG_NONE) { - ma->tree->drag.selected = node->flags & TREE_NODE_SELECTED; + ma->tree->drag.selected = node->flags & TV_NFLAGS_SELECTED; ma->tree->drag.start_node = node; ma->tree->drag.part = part; ma->tree->drag.start.x = ma->x; @@ -3167,7 +3178,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx, if (ma->tree->drag.start_node != NULL && ma->tree->drag.type == TV_DRAG_SELECTION) { - ma->tree->drag.start_node->flags ^= TREE_NODE_SELECTED; + ma->tree->drag.start_node->flags ^= TV_NFLAGS_SELECTED; } } @@ -3212,7 +3223,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx, redraw |= treeview_clear_selection(ma->tree, &r); /* Toggle node expansion */ - if (node->flags & TREE_NODE_EXPANDED) { + if (node->flags & TV_NFLAGS_EXPANDED) { err = treeview_node_contract_internal(ma->tree, node); } else { err = treeview_node_expand_internal(ma->tree, node); @@ -3260,7 +3271,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx, } else if (ma->mouse & BROWSER_MOUSE_PRESS_1 && !(ma->mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_3)) && - !(node->flags & TREE_NODE_SELECTED) && + !(node->flags & TV_NFLAGS_SELECTED) && part != TV_NODE_PART_TOGGLE) { /* Clear any existing selection */ redraw |= treeview_clear_selection(ma->tree, &r); @@ -3272,7 +3283,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx, if (action & TV_NODE_ACTION_SELECTION) { /* Handle change in selection */ - node->flags ^= TREE_NODE_SELECTED; + node->flags ^= TV_NFLAGS_SELECTED; /* Redraw */ if (!redraw) { @@ -3398,7 +3409,7 @@ void treeview_mouse_action(treeview *tree, if (tree->drag.start_node != NULL && tree->drag.type == TV_DRAG_SELECTION) { tree->drag.start_node->flags ^= - TREE_NODE_SELECTED; + TV_NFLAGS_SELECTED; } } @@ -3466,15 +3477,15 @@ static void treeview_init_plot_styles(int font_pt_size) plot_style_even.bg.stroke_width = 0; plot_style_even.bg.stroke_colour = 0; plot_style_even.bg.fill_type = PLOT_OP_TYPE_SOLID; - plot_style_even.bg.fill_colour = gui_system_colour_char("Window"); + plot_style_even.bg.fill_colour = ns_system_colour_char("Window"); /* Text colour */ plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF; plot_style_even.text.size = font_pt_size * FONT_SIZE_SCALE; plot_style_even.text.weight = 400; plot_style_even.text.flags = FONTF_NONE; - plot_style_even.text.foreground = gui_system_colour_char("WindowText"); - plot_style_even.text.background = gui_system_colour_char("Window"); + plot_style_even.text.foreground = ns_system_colour_char("WindowText"); + plot_style_even.text.background = ns_system_colour_char("Window"); /* Entry field text colour */ plot_style_even.itext = plot_style_even.text; @@ -3484,13 +3495,13 @@ static void treeview_init_plot_styles(int font_pt_size) /* Selected background colour */ plot_style_even.sbg = plot_style_even.bg; - plot_style_even.sbg.fill_colour = gui_system_colour_char("Highlight"); + plot_style_even.sbg.fill_colour = ns_system_colour_char("Highlight"); /* Selected text colour */ plot_style_even.stext = plot_style_even.text; plot_style_even.stext.foreground = - gui_system_colour_char("HighlightText"); - plot_style_even.stext.background = gui_system_colour_char("Highlight"); + ns_system_colour_char("HighlightText"); + plot_style_even.stext.background = ns_system_colour_char("Highlight"); /* Selected entry field text colour */ plot_style_even.sitext = plot_style_even.stext; diff --git a/desktop/treeview.h b/desktop/treeview.h index 6fda230b1..0b5bbbbd9 100644 --- a/desktop/treeview.h +++ b/desktop/treeview.h @@ -26,6 +26,7 @@ #include <stdbool.h> #include <stdint.h> +#include "desktop/mouse.h" #include "desktop/core_window.h" #include "desktop/textinput.h" #include "utils/types.h" @@ -34,9 +35,10 @@ typedef struct treeview treeview; typedef struct treeview_node treeview_node; enum treeview_node_type { - TREE_NODE_ROOT = (1 << 0), - TREE_NODE_FOLDER = (1 << 1), - TREE_NODE_ENTRY = (1 << 2) + TREE_NODE_NONE = 0, /**< No node */ + TREE_NODE_ROOT = (1 << 0), /**< Node is treeview's root */ + TREE_NODE_FOLDER = (1 << 1), /**< Node is folder */ + TREE_NODE_ENTRY = (1 << 2) /**< Node is an entry */ }; enum treeview_relationship { @@ -381,8 +383,10 @@ bool treeview_has_selection(treeview *tree); * * \param tree Treeview object to get selected node in * \param node_data Client data for the selected treeview node, or NULL + * \return node type of first selected node. */ -void treeview_get_selection(treeview *tree, void **node_data); +enum treeview_node_type treeview_get_selection(treeview *tree, + void **node_data); /** * Edit the first selected node diff --git a/desktop/version.c b/desktop/version.c index 11544c01b..44d58715f 100644 --- a/desktop/version.c +++ b/desktop/version.c @@ -1,10 +1,10 @@ -#include "utils/testament.h" +#include "testament.h" -const char * const netsurf_version = "3.1 (Dev" +const char * const netsurf_version = "3.3 (Dev" #if defined(CI_BUILD) " CI #" CI_BUILD #endif ")" ; const int netsurf_version_major = 3; -const int netsurf_version_minor = 0; +const int netsurf_version_minor = 3; |