[project @ 2005-02-03 13:18:22 by rjw]

Implementation of URL suggestion

svn path=/import/netsurf/; revision=1488
This commit is contained in:
Richard Wilson 2005-02-03 13:18:22 +00:00
parent 4a34357986
commit 2affb76944
14 changed files with 1174 additions and 20 deletions

View File

@ -22,6 +22,7 @@
#include "netsurf/content/content.h"
#include "netsurf/content/fetchcache.h"
#include "netsurf/content/fetch.h"
#include "netsurf/content/url_store.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/messages.h"
#include "netsurf/utils/url.h"
@ -74,7 +75,7 @@ struct content * fetchcache(const char *url,
struct content *c;
char *url1;
char *hash;
if ((url1 = strdup(url)) == NULL)
return NULL;
@ -210,6 +211,7 @@ void fetchcache_go(struct content *content, char *referer,
void fetchcache_callback(fetch_msg msg, void *p, const char *data,
unsigned long size)
{
struct url_content *url_content;
bool res;
struct content *c = p;
content_type type;
@ -279,6 +281,10 @@ void fetchcache_callback(fetch_msg msg, void *p, const char *data,
break;
case FETCH_FINISHED:
url_content = url_store_find(c->url);
if (url_content)
url_content->requests++;
LOG(("FETCH_FINISHED"));
c->fetch = 0;
content_set_status(c, messages_get("Converting"),

475
content/url_store.c Normal file
View File

@ -0,0 +1,475 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2005 Richard Wilson <info@tinct.net>
*/
/** \file
* Central repository for URL data (implementation).
*/
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netsurf/content/url_store.h"
#include "netsurf/utils/url.h"
#include "netsurf/utils/log.h"
#define ITERATIONS_BEFORE_TEST 32
#define MAXIMUM_URL_LENGTH 1024
struct hostname_data {
char *hostname; /** Hostname (lowercase) */
int hostname_length; /** Length of hostname */
struct url_data *url; /** URLs for this host */
struct hostname_data *previous; /** Previous hostname */
struct hostname_data *next; /** Next hostname */
};
static struct hostname_data *url_store_hostnames = NULL;
static struct hostname_data *url_store_find_hostname(const char *url);
static struct hostname_data *url_store_match_hostname(const char *url,
struct hostname_data *previous);
/**
* Returns the hostname data for the specified URL. If no hostname
* data is currently available then it is created.
*
* \param url the url to find hostname data for
* \return the current hostname data, or NULL on error
*/
static struct hostname_data *url_store_find_hostname(const char *url) {
struct hostname_data *search;
struct hostname_data *result;
url_func_result res;
char *hostname;
int hostname_length;
int compare;
int fast_exit_counter = ITERATIONS_BEFORE_TEST;
assert(url);
res = url_host(url, &hostname);
if (res != URL_FUNC_OK)
return NULL;
hostname_length = strlen(hostname);
/* try to find a matching hostname fairly quickly */
for (search = url_store_hostnames; search; search = search->next) {
if ((fast_exit_counter <= 0) ||
(search->hostname_length == hostname_length)) {
compare = strcmp(hostname, search->hostname);
if (compare == 0) {
free(hostname);
return search;
} else if (compare < 0)
break;
fast_exit_counter = ITERATIONS_BEFORE_TEST;
} else {
fast_exit_counter--;
}
}
/* no hostname is available: create a new one */
result = calloc(sizeof(struct hostname_data), 1);
if (!result)
return NULL;
result->hostname = hostname;
result->hostname_length = hostname_length;
/* simple case: no current hostnames */
if (!url_store_hostnames) {
url_store_hostnames = result;
return result;
}
/* worst case scenario: the place we need to link is within the last
* section of the hostname list so we have no reference to work back
* from. rather than slowing with the very common case of searching,
* we take a speed hit for this case and simply move to the very end
* of the hostname list ready to work backwards. */
if (!search)
for (search = url_store_hostnames; search->next;
search = search->next);
/* we can now simply scan backwards as we know roughly where we need
* to link to (we either had an early exit from the searching so we
* know we're in the block following where we need to link, or we're
* at the very end of the list as we were in the last block.) */
while ((search) && (strcmp(hostname, search->hostname) < 0))
search = search->previous;
/* simple case: our new hostname is the first in the list */
if (!search) {
result->next = url_store_hostnames;
url_store_hostnames->previous = result;
url_store_hostnames = result;
return result;
}
/* general case: link in after the found hostname */
result->previous = search;
result->next = search->next;
if (search->next)
search->next->previous = result;
search->next = result;
return result;
}
/**
* Returns the url data for the specified URL. If no url
* data is currently available then it is created.
*
* \param url a normalized url to find hostname data for
* \return the current hostname data, or NULL on error
*/
struct url_content *url_store_find(const char *url) {
struct hostname_data *hostname_data;
struct url_data *search;
struct url_data *result;
int url_length;
int compare;
int fast_exit_counter = ITERATIONS_BEFORE_TEST;
assert(url);
/* find the corresponding hostname data */
hostname_data = url_store_find_hostname(url);
if (!hostname_data)
return NULL;
/* move to the start of the leafname */
url_length = strlen(url);
/* try to find a matching url fairly quickly */
for (search = hostname_data->url; search; search = search->next) {
if ((fast_exit_counter <= 0) ||
(search->url_length == url_length)) {
compare = strcmp(url, search->url);
if (compare == 0)
return &search->data;
else if (compare < 0)
break;
fast_exit_counter = ITERATIONS_BEFORE_TEST;
} else {
fast_exit_counter--;
}
}
/* no URL is available: create a new one */
result = calloc(sizeof(struct url_data), 1);
if (!result)
return NULL;
result->url = malloc(url_length + 1);
if (!result->url) {
free(result);
return NULL;
}
strcpy(result->url, url);
result->url_length = url_length;
result->data.requests = 0;
result->data.visits = 0;
result->parent = hostname_data;
/* simple case: no current URLs */
if (!hostname_data->url) {
hostname_data->url = result;
return &result->data;
}
/* worst case scenario: the place we need to link is within the last
* section of the URL list so we have no reference to work back
* from. rather than slowing with the very common case of searching,
* we take a speed hit for this case and simply move to the very end
* of the URL list ready to work backwards. */
if (!search)
for (search = hostname_data->url; search->next;
search = search->next);
/* we can now simply scan backwards as we know roughly where we need
* to link to (we either had an early exit from the searching so we
* know we're in the block following where we need to link, or we're
* at the very end of the list as we were in the last block.) */
while ((search) && (strcmp(url, search->url) < 0))
search = search->previous;
/* simple case: our new hostname is the first in the list */
if (!search) {
result->next = hostname_data->url;
hostname_data->url->previous = result;
hostname_data->url = result;
return &result->data;
}
/* general case: link in after the found hostname */
result->previous = search;
result->next = search->next;
if (search->next)
search->next->previous = result;
search->next = result;
return &result->data;
}
/**
* Returns the next hostname that matches a part of the specified URL.
*
* \param url a normalized url to find the next match for
* \param current the current hostname to search forward from, or NULL
* \return the next matching hostname, or NULL
*/
static struct hostname_data *url_store_match_hostname(const char *url,
struct hostname_data *current) {
url_func_result res;
char *hostname;
int hostname_length;
int compare;
bool www_test;
assert(url);
res = url_host(url, &hostname);
if (res != URL_FUNC_OK)
return NULL;
hostname_length = strlen(hostname);
www_test = strncmp(hostname, "www.", 4);
/* advance to the next hostname */
if (!current)
current = url_store_hostnames;
else
current = current->next;
/* skip past hostname data without URLs */
for (; current && (!current->url); current = current->next);
while (current) {
if (current->hostname_length >= hostname_length) {
compare = strncmp(hostname, current->hostname,
hostname_length);
if (compare == 0) {
free(hostname);
return current;
} else if ((compare < 0) && !www_test)
break;
}
/* special case: if hostname is not www then try it */
if (www_test && ((current->hostname_length - 4) >= hostname_length) &&
(!strncmp(current->hostname, "www.", 4)) &&
(!strncmp(hostname, current->hostname + 4,
hostname_length))) {
free(hostname);
return current;
}
/* move to next hostname with URLs */
current = current->next;
for (; current && (!current->url); current = current->next);
}
free(hostname);
return NULL;
}
/**
* Returns the complete URL for the next matched stored URL.
*
* \param url a normalized url to find the next match for
* \param reference internal reference (NULL for first call)
* \return the next URL that matches
*/
char *url_store_match(const char *url, struct url_data **reference) {
struct hostname_data *hostname;
struct url_data *search = NULL;
char *scheme;
int scheme_length;
int url_length;
url_func_result res;
bool www_test;
assert(url);
if (!url_store_hostnames)
return NULL;
/* find the first URL, not necessarily matching */
if (!*reference) {
hostname = url_store_match_hostname(url, NULL);
if (!hostname)
return NULL;
} else {
search = *reference;
hostname = search->parent;
}
res = url_scheme(url, &scheme);
if (res != URL_FUNC_OK)
return NULL;
scheme_length = strlen(scheme);
url_length = strlen(url);
www_test = (!strcmp(scheme, "http") &&
strncmp(url + 4 + 3, "www.", 4)); /* 'http' + '://' */
/* work through all our strings, ignoring the scheme and 'www.' */
while (hostname) {
/* get the next URL to test */
if (!search)
search = hostname->url;
else
search = search->next;
/* loop past end of list, or search */
if (!search) {
hostname = url_store_match_hostname(url, hostname);
if (!hostname)
return NULL;
} else if ((search->data.visits > 0) && (search->data.requests > 0)){
/* straight match */
if ((search->url_length >= url_length) &&
(!strncmp(search->url, url, url_length))) {
free(scheme);
*reference = search;
return search->url;
}
/* try with 'www.' inserted after the scheme */
if (www_test && ((search->url_length - 4) >= url_length) &&
(!strncmp(search->url, scheme, scheme_length)) &&
(!strncmp(search->url + scheme_length + 3, "www.", 4)) &&
(!strncmp(search->url + scheme_length + 7,
url + scheme_length + 3,
url_length - scheme_length - 3))) {
free(scheme);
*reference = search;
return search->url;
}
}
}
free(scheme);
return NULL;
}
/**
* Converts a text string into one suitable for URL matching.
*
* \param text the text to search with
* \return URL matching string allocated on heap, or NULL on error
*/
char *url_store_match_string(const char *text) {
url_func_result res;
char *url;
assert(text);
res = url_normalize(text, &url);
if (res != URL_FUNC_OK)
return NULL;
/* drop the '/' from the end if it was added when normalizing */
if ((url[strlen(url) - 1] == '/') && (text[strlen(text) - 1] != '/'))
url[strlen(url) - 1] = '\0';
return url;
}
/**
* Loads the current contents of the URL store to disk
*
* \param file the file to load options from
*/
void url_store_load(const char *file) {
struct url_content *url;
char s[MAXIMUM_URL_LENGTH];
FILE *fp;
fp = fopen(file, "r");
if (!fp) {
LOG(("Failed to open file '%s' for reading", file));
return;
}
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
return;
if (strncmp(s, "100", 3)) {
LOG(("Invalid header"));
return;
}
while (fgets(s, MAXIMUM_URL_LENGTH, fp)) {
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = '\0';
url = url_store_find(s);
if (!url)
break;
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
url->visits = atoi(s);
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
url->requests = atoi(s);
}
fclose(fp);
}
/**
* Saves the current contents of the URL store to disk
*
* \param file the file to load options from
*/
void url_store_save(const char *file) {
struct hostname_data *search;
struct url_data *url;
FILE *fp;
fp = fopen(file, "w");
if (!fp) {
LOG(("Failed to open file '%s' for writing", file));
return;
}
/* file format version number */
fprintf(fp, "100\n");
for (search = url_store_hostnames; search; search = search->next) {
for (url = search->url; url; url = url->next) {
if (strlen(url->url) < 1024) {
fprintf(fp, "%s\n%i\n%i\n", url->url,
url->data.visits, url->data.requests);
}
}
}
fclose(fp);
}
/**
* Dumps the currently stored URLs and hostnames to stderr.
*/
void url_store_dump(void) {
struct hostname_data *search;
struct url_data *url;
fprintf(stderr, "\nDumping hostname data:\n");
for (search = url_store_hostnames; search; search = search->next) {
fprintf(stderr, "\n");
fprintf(stderr, search->hostname);
fprintf(stderr, ":\n");
for (url = search->url; url; url = url->next) {
fprintf(stderr, " - ");
fprintf(stderr, url->url);
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\nEnd of hostname data.\n\n");
}

39
content/url_store.h Normal file
View File

@ -0,0 +1,39 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2005 Richard Wilson <info@tinct.net>
*/
/** \file
* Central repository for URL data (interface).
*/
#ifndef _NETSURF_CONTENT_URLSTORE_H_
#define _NETSURF_CONTENT_URLSTORE_H_
struct url_content {
int visits; /** Number of times visited */
int requests; /** Number of times requested */
};
struct url_data {
struct url_content data; /** Stored URL content data */
char *url; /** URL (including hostname) */
int url_length; /** Length of URL (including hostname) */
struct url_data *previous; /** Previous URL */
struct url_data *next; /** Next URL */
struct hostname_data *parent; /** Parent hostname data */
};
struct url_content *url_store_find(const char *url);
char *url_store_match(const char *url, struct url_data **reference);
char *url_store_match_string(const char *text);
void url_store_load(const char *file);
void url_store_save(const char *file);
void url_store_dump(void);
#endif

View File

@ -22,6 +22,7 @@
#include "netsurf/utils/config.h"
#include "netsurf/content/fetch.h"
#include "netsurf/content/fetchcache.h"
#include "netsurf/content/url_store.h"
#include "netsurf/css/css.h"
#ifdef WITH_AUTH
#include "netsurf/desktop/401login.h"
@ -166,6 +167,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
char *url2;
char *hash;
url_func_result res;
struct url_content *url_content;
LOG(("bw %p, url %s", bw, url));
@ -194,6 +196,10 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
bw->frag_id = strdup(hash+1);
}
url_content = url_store_find(url2);
if (url_content)
url_content->visits++;
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = history_add;
bw->time0 = clock();

View File

@ -17,7 +17,7 @@
# "riscos", "riscos_small", "ncos", and "riscos_debug" can be compiled under
# RISC OS, or cross-compiled using gccsdk.
OBJECTS_COMMON = content.o fetch.o fetchcache.o # content/
OBJECTS_COMMON = content.o fetch.o fetchcache.o url_store.o # content/
OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
OBJECTS_COMMON += box.o form.o html.o html_redraw.o layout.o \
list.o textplain.o # render/
@ -35,7 +35,7 @@ OBJECTS_RISCOS += 401login.o bitmap.o buffer.o debugwin.o \
save.o save_complete.o save_draw.o save_text.o \
schedule.o search.o sprite.o textselection.o theme.o \
theme_install.o thumbnail.o treeview.o ufont.o uri.o \
url_protocol.o wimp.o window.o # riscos/
url_complete.o url_protocol.o wimp.o window.o # riscos/
# OBJECTS_RISCOS += memdebug.o
OBJECTS_NCOS = $(OBJECTS_RISCOS)

View File

@ -43,7 +43,7 @@ wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br,
dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip,
dialog_warning, dialog_config_th_pane, dialog_debug,
dialog_folder, dialog_entry, dialog_search, dialog_print,
dialog_config_font, dialog_config_image;
dialog_config_font, dialog_config_image, dialog_url_complete;
static int ro_gui_choices_font_size;
static int ro_gui_choices_font_min_size;
@ -140,6 +140,7 @@ void ro_gui_dialog_init(void)
dialog_config_font = ro_gui_dialog_create("config_font");
dialog_config_image = ro_gui_dialog_create("config_img");
dialog_theme_install = ro_gui_dialog_create("theme_inst");
dialog_url_complete = ro_gui_dialog_create("url_suggest");
}
@ -811,12 +812,8 @@ void ro_gui_save_options(void)
/* NCOS doesnt have the fancy Universal Boot vars; so select
* the path to the choices file based on the build options */
#ifndef NCOS
xosfile_create_dir("<Choices$Write>.WWW", 0);
xosfile_create_dir("<Choices$Write>.WWW.NetSurf", 0);
options_write("<Choices$Write>.WWW.NetSurf.Choices");
#else
xosfile_create_dir("<User$Path>.Choices.NetSurf", 0);
xosfile_create_dir("<User$Path>.Choices.NetSurf.Choices", 0);
options_write("<User$Path>.Choices.NetSurf.Choices");
#endif
}

View File

@ -32,6 +32,7 @@
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
#include "oslib/uri.h"
#include "netsurf/content/url_store.h"
#include "netsurf/utils/config.h"
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/netsurf.h"
@ -57,6 +58,7 @@
#ifdef WITH_URL
#include "netsurf/riscos/url_protocol.h"
#endif
#include "netsurf/riscos/url_complete.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/messages.h"
@ -184,6 +186,17 @@ void gui_init(int argc, char** argv)
xhourglass_start(1);
/* create our choices directories */
#ifndef NCOS
xosfile_create_dir("<Choices$Write>.WWW", 0);
xosfile_create_dir("<Choices$Write>.WWW.NetSurf", 0);
xosfile_create_dir("<Choices$Write>.WWW.NetSurf.Themes", 0);
#else
xosfile_create_dir("<User$Path>.Choices.NetSurf", 0);
xosfile_create_dir("<User$Path>.Choices.NetSurf.Choices", 0);
xosfile_create_dir("<User$Path>.Choices.NetSurf.Choices.Themes", 0);
#endif
#ifdef WITH_SAVE_COMPLETE
save_complete_init();
#endif
@ -195,6 +208,8 @@ void gui_init(int argc, char** argv)
options_read("<User$Path>.Choices.NetSurf.Choices");
#endif
ro_gui_choose_language();
url_store_load("Choices:WWW.NetSurf.URL");
NETSURF_DIR = getenv("NetSurf$Dir");
if ((length = snprintf(path, sizeof(path),
@ -527,6 +542,7 @@ void gui_init2(int argc, char** argv)
void gui_quit(void)
{
url_store_save("<Choices$Write>.WWW.NetSurf.URL");
ro_gui_window_quit();
ro_gui_hotlist_save();
ro_gui_history_quit();
@ -751,6 +767,8 @@ void ro_gui_null_reason_code(void)
if (gui_track_wimp_w == history_window)
ro_gui_history_mouse_at(&pointer);
if (gui_track_wimp_w == dialog_url_complete)
ro_gui_url_complete_mouse_at(&pointer);
else if (gui_track_gui_window)
ro_gui_window_mouse_at(gui_track_gui_window, &pointer);
}
@ -766,6 +784,8 @@ void ro_gui_redraw_window_request(wimp_draw *redraw)
if (redraw->w == history_window)
ro_gui_history_redraw(redraw);
else if (redraw->w == dialog_url_complete)
ro_gui_url_complete_redraw(redraw);
else if ((hotlist_tree) && (redraw->w == (wimp_w)hotlist_tree->handle))
ro_gui_tree_redraw(redraw, hotlist_tree);
else if ((hotlist_toolbar) && (hotlist_toolbar->toolbar_handle == redraw->w))
@ -827,8 +847,10 @@ void ro_gui_close_window_request(wimp_close *close)
if (close->w == dialog_debug)
ro_gui_debugwin_close();
else if ((g = ro_gui_window_lookup(close->w)) != NULL)
else if ((g = ro_gui_window_lookup(close->w)) != NULL) {
ro_gui_url_complete_close(NULL, 0);
browser_window_destroy(g->bw);
}
else if ((dw = ro_gui_download_window_lookup(close->w)) != NULL)
ro_gui_download_window_destroy(dw);
else
@ -866,7 +888,8 @@ void ro_gui_pointer_entering_window(wimp_entering *entering)
{
gui_track_wimp_w = entering->w;
gui_track_gui_window = ro_gui_window_lookup(entering->w);
gui_track = gui_track_gui_window || gui_track_wimp_w == history_window;
gui_track = gui_track_gui_window || gui_track_wimp_w == history_window ||
gui_track_wimp_w == dialog_url_complete;
}
@ -883,6 +906,8 @@ void ro_gui_mouse_click(wimp_pointer *pointer)
ro_gui_icon_bar_click(pointer);
else if (pointer->w == history_window)
ro_gui_history_click(pointer);
else if (pointer->w == dialog_url_complete)
ro_gui_url_complete_mouse_at(pointer);
else if ((hotlist_tree) && (pointer->w == (wimp_w)hotlist_tree->handle))
ro_gui_hotlist_click(pointer);
else if (pointer->w == dialog_saveas)

View File

@ -30,7 +30,8 @@ extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br,
dialog_config_prox, dialog_config_th, dialog_zoom, dialog_pageinfo,
dialog_objinfo, dialog_tooltip, dialog_warning,
dialog_config_th_pane, dialog_debug, dialog_folder, dialog_entry,
dialog_search, dialog_print, dialog_config_font, dialog_theme_install;
dialog_search, dialog_print, dialog_config_font, dialog_theme_install,
dialog_url_complete;
extern wimp_w history_window;
extern wimp_menu *iconbar_menu, *browser_menu, *combo_menu, *hotlist_menu,
*proxyauth_menu, *languages_menu, *toolbar_menu,

View File

@ -152,11 +152,6 @@ void ro_gui_hotlist_save(void) {
if (!hotlist_tree) return;
/* Ensure we have a directory to save to later.
*/
xosfile_create_dir("<Choices$Write>.WWW", 0);
xosfile_create_dir("<Choices$Write>.WWW.NetSurf", 0);
/* Save to our file
*/
options_save_hotlist(hotlist_tree, "<Choices$Write>.WWW.NetSurf.Hotlist");

View File

@ -12,6 +12,8 @@
#ifndef _NETSURF_RISCOS_SPRITE_H_
#define _NETSURF_RISCOS_SPRITE_H_
#include <stdbool.h>
struct content;
struct content_sprite_data {

558
riscos/url_complete.c Normal file
View File

@ -0,0 +1,558 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2005 Richard Wilson <info@tinct.net>
*/
/** \file
* GUI URL auto-completion (implementation).
*/
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "oslib/wimp.h"
#include "netsurf/content/url_store.h"
#include "netsurf/utils/log.h"
#include "netsurf/riscos/gui.h"
#include "netsurf/riscos/theme.h"
#include "netsurf/riscos/url_complete.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/utils.h"
#define MAXIMUM_VISIBLE_LINES 7
static char **url_complete_matches = NULL;
static int url_complete_matches_allocated = 0;
static int url_complete_matches_available = 0;
static char *url_complete_matched_string = NULL;
static int url_complete_matches_selection = -1;
static int url_complete_keypress_selection = -1;
static wimp_w url_complete_parent = 0;
static bool url_complete_matches_reset = false;
static char *url_complete_original_url = NULL;
static char *url_complete_redraw[MAXIMUM_VISIBLE_LINES];
static char url_complete_icon_null[] = "\0";
static wimp_icon url_complete_icon;
static int mouse_x;
static int mouse_y;
/**
* Handles a keypress for URL completion
*
* \param g the gui_window to update
* \param key the key pressed
*/
bool ro_gui_url_complete_keypress(struct gui_window *g, int key) {
wimp_window_state state;
char **array_extend;
struct url_data *reference = NULL;
char *match_url;
char *url;
char *output;
int i, lines;
int old_selection;
bool ignore_changes = false;
int height;
os_error *error;
bool currently_open;
/* we must have a toolbar/url bar */
if ((!g->toolbar) || (!g->toolbar->display_url)) {
ro_gui_url_complete_close(NULL, 0);
return false;
}
/* if we are currently active elsewhere, remove the previous window */
currently_open = g->window == url_complete_parent;
if (g->window != url_complete_parent) {
ro_gui_url_complete_close(NULL, 0);
url_complete_parent = g->window;
}
/* get the text to match */
url = ro_gui_get_icon_string(g->toolbar->toolbar_handle, ICON_TOOLBAR_URL);
match_url = url_store_match_string(url);
if (!match_url) {
ro_gui_url_complete_close(NULL, 0);
return false;
}
/* check if we should ignore text changes */
if (url_complete_keypress_selection >= 0)
ignore_changes = !strcmp(url,
url_complete_matches[url_complete_keypress_selection]);
/* if the text to match has changed then update it */
if (!ignore_changes && ((!url_complete_matched_string) ||
(strcmp(match_url, url_complete_matched_string)))) {
/* memorize the current matches */
lines = MAXIMUM_VISIBLE_LINES;
if (lines > url_complete_matches_available)
lines = url_complete_matches_available;
for (i = 0; i < MAXIMUM_VISIBLE_LINES; i++)
url_complete_redraw[i] = url_complete_matches[i];
/* our selection gets wiped */
error = xwimp_force_redraw(dialog_url_complete,
0, -(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
/* clear our state */
free(url_complete_original_url);
free(url_complete_matched_string);
url_complete_matched_string = match_url;
url_complete_original_url = NULL;
url_complete_matches_available = 0;
url_complete_matches_selection = -1;
url_complete_keypress_selection = -1;
/* get some initial memory */
if (!url_complete_matches) {
url_complete_matches = malloc(64 * sizeof(char *));
if (!url_complete_matches) {
ro_gui_url_complete_close(NULL, 0);
return false;
}
url_complete_matches_allocated = 64;
}
/* get all our matches */
while ((output = url_store_match(match_url, &reference))) {
url_complete_matches_available++;
if (url_complete_matches_available >
url_complete_matches_allocated) {
array_extend = realloc(url_complete_matches,
(url_complete_matches_allocated + 64) *
sizeof(char *));
if (!array_extend) {
ro_gui_url_complete_close(NULL, 0);
return false;
}
url_complete_matches = array_extend;
url_complete_matches_allocated += 64;
}
url_complete_matches[url_complete_matches_available - 1] =
output;
}
/* update the window */
state.w = g->window;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return false;
}
url_complete_matches_reset = true;
ro_gui_url_complete_resize(g, (wimp_open *)&state);
url_complete_matches_reset = false;
/* redraw the relevant bits of the window */
lines = MAXIMUM_VISIBLE_LINES;
if (lines > url_complete_matches_available)
lines = url_complete_matches_available;
for (i = 0; i < MAXIMUM_VISIBLE_LINES; i++) {
if (url_complete_redraw[i] != url_complete_matches[i]) {
error = xwimp_force_redraw(dialog_url_complete,
0, -(i + 1) * 44, 65536, -i * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
}
}
} else {
free(match_url);
}
/* handle keypresses */
if (!currently_open)
return false;
old_selection = url_complete_matches_selection;
switch (key) {
case wimp_KEY_UP:
url_complete_matches_selection--;
break;
case wimp_KEY_DOWN:
url_complete_matches_selection++;
break;
case wimp_KEY_PAGE_UP:
url_complete_matches_selection -= MAXIMUM_VISIBLE_LINES;
break;
case wimp_KEY_PAGE_DOWN:
url_complete_matches_selection += MAXIMUM_VISIBLE_LINES;
break;
case wimp_KEY_CONTROL | wimp_KEY_UP:
url_complete_matches_selection = 0;
break;
case wimp_KEY_CONTROL | wimp_KEY_DOWN:
url_complete_matches_selection = 65536;
break;
}
if (url_complete_matches_selection > url_complete_matches_available - 1)
url_complete_matches_selection = url_complete_matches_available - 1;
else if (url_complete_matches_selection < -1)
url_complete_matches_selection = -1;
if (old_selection == url_complete_matches_selection)
return false;
error = xwimp_force_redraw(dialog_url_complete,
0, -(old_selection + 1) * 44, 65536, -old_selection * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
error = xwimp_force_redraw(dialog_url_complete,
0, -(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
if (old_selection == -1) {
free(url_complete_original_url);
url_complete_original_url = malloc(strlen(url) + 1);
if (!url_complete_original_url)
return false;
strcpy(url_complete_original_url, url);
}
if (url_complete_matches_selection == -1) {
ro_gui_set_icon_string(g->toolbar->toolbar_handle,
ICON_TOOLBAR_URL,
url_complete_original_url);
} else {
ro_gui_set_icon_string(g->toolbar->toolbar_handle,
ICON_TOOLBAR_URL,
url_complete_matches[url_complete_matches_selection]);
}
url_complete_keypress_selection = url_complete_matches_selection;
/* auto-scroll */
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return true;
}
if (state.yscroll < -(url_complete_matches_selection * 44))
state.yscroll = -(url_complete_matches_selection * 44);
height = state.visible.y1 - state.visible.y0;
if (state.yscroll - height > -((url_complete_matches_selection + 1) * 44))
state.yscroll = -((url_complete_matches_selection + 1) * 44) + height;
error = xwimp_open_window((wimp_open *)(&state));
if (error) {
LOG(("xwimp_open_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return true;
}
return true;
}
/**
* Move and resize the url completion window to match the toolbar.
*
* \param g the gui_window to update
* \param open the wimp_open request (updated on exit)
*/
void ro_gui_url_complete_resize(struct gui_window *g, wimp_open *open) {
os_box extent = { 0, 0, 0, 0 };
wimp_icon_state url_state;
wimp_window_state toolbar_state;
wimp_window_state state;
os_error *error;
int lines;
int scroll_v = 0;
/* if we the URL completion isn't for our window, or there is no toolbar,
* or there is no URL bar shown, or there are no URL matches, close it */
if ((open->w != url_complete_parent) || (!g->toolbar) ||
(!g->toolbar->display_url) ||
(url_complete_matches_available == 0)) {
ro_gui_url_complete_close(NULL, 0);
return;
}
/* get our current auto-complete window state for the scroll values */
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
if (url_complete_matches_reset)
state.yscroll = 0;
/* move the window to the correct position */
toolbar_state.w = g->toolbar->toolbar_handle;
error = xwimp_get_window_state(&toolbar_state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
url_state.w = g->toolbar->toolbar_handle;
url_state.i = ICON_TOOLBAR_URL;
error = xwimp_get_icon_state(&url_state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
lines = url_complete_matches_available;
extent.y0 = -(lines * 44);
extent.x1 = 65536;
error = xwimp_set_extent(dialog_url_complete, &extent);
if (error) {
LOG(("xwimp_set_extent: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
state.next = open->next;
state.flags &= ~wimp_WINDOW_VSCROLL;
state.flags &= ~(4095 << 16); /* clear bits 16-27 */
if (lines > MAXIMUM_VISIBLE_LINES) {
lines = MAXIMUM_VISIBLE_LINES;
scroll_v = ro_get_vscroll_width(NULL) - 2;
state.flags |= wimp_WINDOW_VSCROLL;
}
state.visible.x0 = open->visible.x0 + 2 + url_state.icon.extent.x0;
state.visible.x1 = open->visible.x0 - 2 + url_state.icon.extent.x1 - scroll_v;
state.visible.y1 = open->visible.y1 - url_state.icon.extent.y1 + 2;
state.visible.y0 = state.visible.y1 - (lines * 44);
if (state.visible.x1 > toolbar_state.visible.x1)
state.visible.x1 = toolbar_state.visible.x1;
if (state.visible.x1 - state.visible.x0 - scroll_v < 0) {
error = xwimp_close_window(dialog_url_complete);
if (error) {
LOG(("xwimp_close_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
} else {
error = xwimp_open_window_nested_with_flags(&state, (wimp_w)-1, 0);
if (error) {
LOG(("xwimp_open_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
open->next = dialog_url_complete;
}
}
/**
* Try to close the current url completion window
*
* \param g the gui_window the user clicked on (or NULL to forcibly close)
* \param i the icon the user clicked on to prompt the close
* \return whether the window was closed
*/
bool ro_gui_url_complete_close(struct gui_window *g, wimp_i i) {
os_error *error;
if ((g && (i == ICON_TOOLBAR_URL) && (g->window == url_complete_parent)))
return false;
free(url_complete_matches);
free(url_complete_matched_string);
free(url_complete_original_url);
url_complete_matches = NULL;
url_complete_matched_string = NULL;
url_complete_original_url = NULL;
url_complete_matches_allocated = 0;
url_complete_matches_available = 0;
url_complete_keypress_selection = -1;
url_complete_matches_selection = -1;
url_complete_parent = 0;
error = xwimp_close_window(dialog_url_complete);
if (error) {
LOG(("xwimp_close_window: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
return true;
}
/**
* Redraws a section of the URL completion window
*
* \param redraw the area to redraw
* \param tree the tree to redraw
*/
void ro_gui_url_complete_redraw(wimp_draw *redraw) {
osbool more;
os_error *error;
int clip_y0, clip_y1, origin_y;
int first_line, last_line, line;
/* initialise our icon */
url_complete_icon.flags = wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED |
wimp_ICON_TEXT | wimp_ICON_FILLED |
(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT);
url_complete_icon.extent.x0 = 0;
url_complete_icon.extent.x1 = 16384;
url_complete_icon.data.indirected_text.validation = url_complete_icon_null;
/* redraw */
more = wimp_redraw_window(redraw);
while (more) {
origin_y = redraw->box.y1 - redraw->yscroll;
clip_y0 = redraw->clip.y0 - origin_y;
clip_y1 = redraw->clip.y1 - origin_y;
first_line = (-clip_y1) / 44;
last_line = (-clip_y0 + 43) / 44;
for (line = first_line; line < last_line; line++) {
if (line == url_complete_matches_selection)
url_complete_icon.flags |= wimp_ICON_SELECTED;
else
url_complete_icon.flags &= ~wimp_ICON_SELECTED;
url_complete_icon.extent.y1 = -line * 44;
url_complete_icon.extent.y0 = -(line + 1) * 44;
url_complete_icon.data.indirected_text.text =
url_complete_matches[line];
url_complete_icon.data.indirected_text.size =
strlen(url_complete_matches[line]);
error = xwimp_plot_icon(&url_complete_icon);
if (error) {
LOG(("xwimp_plot_icon: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
}
more = wimp_get_rectangle(redraw);
}
}
/**
* Handle mouse movements/clicks over the URL completion window.
*/
void ro_gui_url_complete_mouse_at(wimp_pointer *pointer) {
wimp_window_state state;
os_error *error;
int selection, old_selection;
struct gui_window *g;
char *url;
if ((mouse_x == pointer->pos.x) && (mouse_y == pointer->pos.y) &&
(pointer->buttons == 0))
return;
mouse_x = pointer->pos.x;
mouse_y = pointer->pos.y;
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
return;
}
selection = (state.visible.y1 - pointer->pos.y - state.yscroll) / 44;
if (selection != url_complete_matches_selection) {
if (url_complete_matches_selection == -1) {
g = ro_gui_window_lookup(url_complete_parent);
if (!g)
return;
url = ro_gui_get_icon_string(g->toolbar->toolbar_handle,
ICON_TOOLBAR_URL);
free(url_complete_original_url);
url_complete_original_url = malloc(strlen(url) + 1);
if (!url_complete_original_url)
return;
strcpy(url_complete_original_url, url);
}
old_selection = url_complete_matches_selection;
url_complete_matches_selection = selection;
error = xwimp_force_redraw(dialog_url_complete,
0, -(old_selection + 1) * 44, 65536, -old_selection * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
error = xwimp_force_redraw(dialog_url_complete,
0, -(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
LOG(("xwimp_force_redraw: 0x%x: %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
}
/* clicks */
if ((pointer->buttons == wimp_CLICK_SELECT) ||
(pointer->buttons == wimp_CLICK_ADJUST)) {
g = ro_gui_window_lookup(url_complete_parent);
if (!g)
return;
ro_gui_set_icon_string(g->toolbar->toolbar_handle,
ICON_TOOLBAR_URL,
url_complete_matches[url_complete_matches_selection]);
browser_window_go(g->bw,
url_complete_matches[url_complete_matches_selection],
0);
ro_gui_url_complete_close(NULL, 0);
}
}
/**
* Dumps all matching URLs to stderr.
*/
void url_complete_dump_matches(const char *url) {
char *match_url;
struct url_data *reference = NULL;
char *output;
match_url = url_store_match_string(url);
if (!match_url)
return;
fprintf(stderr, "\nDumping matches for '%s' ('%s'):\n", url, match_url);
while ((output = url_store_match(match_url, &reference))) {
fprintf(stderr, " - ");
fprintf(stderr, output);
fprintf(stderr, "\n");
}
fprintf(stderr, "\nEnd of matches.\n\n");
free(match_url);
}

26
riscos/url_complete.h Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2005 Richard Wilson <info@tinct.net>
*/
/** \file
* Central repository for URL data (interface).
*/
#ifndef _NETSURF_RISCOS_URLCOMPLETE_H_
#define _NETSURF_RISCOS_URLCOMPLETE_H_
#include <stdbool.h>
#include "netsurf/riscos/gui.h"
bool ro_gui_url_complete_keypress(struct gui_window *g, int key);
void ro_gui_url_complete_resize(struct gui_window *g, wimp_open *open);
bool ro_gui_url_complete_close(struct gui_window *g, wimp_i i);
void ro_gui_url_complete_redraw(wimp_draw *redraw);
void ro_gui_url_complete_mouse_at(wimp_pointer *pointer);
void url_complete_dump_matches(const char *url);
#endif

View File

@ -25,6 +25,7 @@
#include "oslib/wimpspriteop.h"
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h"
#include "netsurf/content/url_store.h"
#include "netsurf/css/css.h"
#include "netsurf/desktop/plotters.h"
#include "netsurf/render/box.h"
@ -35,6 +36,7 @@
#include "netsurf/riscos/theme.h"
#include "netsurf/riscos/thumbnail.h"
#include "netsurf/riscos/treeview.h"
#include "netsurf/riscos/url_complete.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/url.h"
@ -929,6 +931,9 @@ void ro_gui_window_open(struct gui_window *g, wimp_open *open)
}
/* first resize stops any flickering by making the URL window on top */
ro_gui_url_complete_resize(g, open);
error = xwimp_open_window(open);
if (error) {
LOG(("xwimp_open_window: 0x%x: %s",
@ -957,8 +962,11 @@ void ro_gui_window_open(struct gui_window *g, wimp_open *open)
g->old_height = height;
}
if (g->toolbar)
if (g->toolbar) {
ro_gui_theme_process_toolbar(g->toolbar, -1);
/* second resize updates to the new URL bar width */
ro_gui_url_complete_resize(g, open);
}
}
@ -1090,6 +1098,9 @@ void ro_gui_toolbar_click(struct gui_window *g, wimp_pointer *pointer)
/* Store the toolbar
*/
current_toolbar = g->toolbar;
/* try to close url-completion */
ro_gui_url_complete_close(g, pointer->i);
/* Handle Menu clicks
*/
@ -1232,6 +1243,9 @@ void ro_gui_window_click(struct gui_window *g, wimp_pointer *pointer)
assert(g);
/* try to close url-completion */
ro_gui_url_complete_close(g, pointer->i);
xosbyte1(osbyte_SCAN_KEYBOARD, 0 ^ 0x80, 0, &shift);
state.w = pointer->w;
@ -1486,6 +1500,10 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
ro_gui_view_source(content);
return true;
case wimp_KEY_CONTROL + wimp_KEY_F8: /* Dump url_store. */
url_store_dump();
return true;
case wimp_KEY_F9: /* Dump content for debugging. */
switch (content->type) {
case CONTENT_HTML:
@ -1513,6 +1531,7 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
case wimp_KEY_RETURN:
if (!toolbar)
break;
ro_gui_url_complete_close(NULL, 0);
toolbar_url = ro_gui_get_icon_string(g->toolbar->toolbar_handle,
ICON_TOOLBAR_URL);
res = url_normalize(toolbar_url, &url);
@ -1524,6 +1543,8 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
return true;
case wimp_KEY_ESCAPE:
if (ro_gui_url_complete_close(0, 0))
return true;
browser_window_stop(g->bw);
return true;
@ -1569,9 +1590,12 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
case wimp_KEY_PAGE_DOWN:
case wimp_KEY_CONTROL | wimp_KEY_UP:
case wimp_KEY_CONTROL | wimp_KEY_DOWN:
if (toolbar)
return ro_gui_url_complete_keypress(g, key);
break;
default:
if (toolbar)
return ro_gui_url_complete_keypress(g, key);
return false;
}
@ -1601,7 +1625,7 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
break;
}
wimp_open_window((wimp_open *) &state);
wimp_open_window((wimp_open *) &state);
return true;
}

View File

@ -77,7 +77,7 @@ url_func_result url_normalize(const char *url, char **result)
if (match[1].rm_so == -1) {
/* scheme missing: add http:// and reparse */
LOG(("scheme missing: using http"));
/* LOG(("scheme missing: using http"));*/
if ((*result = malloc(len + 13)) == NULL) {
LOG(("malloc failed"));
return URL_FUNC_NOMEM;