From 811106028fd050cdee11fbc8732ba39f2de5e12a Mon Sep 17 00:00:00 2001 From: Phil Mellor Date: Wed, 11 Sep 2002 14:24:02 +0000 Subject: [project @ 2002-09-11 14:24:02 by monkeyson] RISC OS Wimp GUI. svn path=/import/netsurf/; revision=33 --- desktop/browser.c | 800 ++++++++++++++++++++++++++++++++++++++++ desktop/browser.h | 148 ++++++++ desktop/fetch.c | 344 +++++++++++++++++ desktop/fetch.h | 49 +++ desktop/gui.h | 45 +++ desktop/netsurf.c | 50 +++ desktop/netsurf.h | 35 ++ makefile | 19 +- render/box.c | 4 +- render/layout.c | 4 +- riscos/font.c | 86 ++++- riscos/font.h | 39 ++ riscos/gui.c | 1057 +++++++++++++++++++++++++++++++++++++++++++++++++++++ riscos/gui.h | 47 +++ utils/utils.c | 10 +- 15 files changed, 2724 insertions(+), 13 deletions(-) create mode 100644 desktop/browser.c create mode 100644 desktop/browser.h create mode 100644 desktop/fetch.c create mode 100644 desktop/fetch.h create mode 100644 desktop/gui.h create mode 100644 desktop/netsurf.c create mode 100644 desktop/netsurf.h create mode 100644 riscos/font.h create mode 100644 riscos/gui.c create mode 100644 riscos/gui.h diff --git a/desktop/browser.c b/desktop/browser.c new file mode 100644 index 000000000..f21008abb --- /dev/null +++ b/desktop/browser.c @@ -0,0 +1,800 @@ +/** + * $Id: browser.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#include "netsurf/riscos/font.h" +#include "netsurf/render/box.h" +#include "netsurf/render/layout.h" +#include "netsurf/render/css.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/render/utils.h" +#include +#include +#include +#include + +struct box_selection +{ + struct box* box; + int actual_x; + int actual_y; + int plot_index; +}; + +void browser_window_text_selection(struct browser_window* bw, int click_x, int click_y, int click_type); +void browser_window_clear_text_selection(struct browser_window* bw); +void browser_window_change_text_selection(struct browser_window* bw, struct box_position* new_start, struct box_position* new_end); +void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end); +void browser_window_follow_link(struct browser_window* bw, + int click_x, int click_y, int click_type); + +void box_under_area(struct box* box, int x, int y, int ox, int oy, struct box_selection** found, int* count, int* plot_index); + + +void content_destroy(struct content* c) +{ + if (c == NULL) + return; + + switch (c->type) + { + case CONTENT_HTML: + /* free other memory here */ + break; + default: + break; + } + + c->main_fetch = fetch_cancel(c->main_fetch); + xfree(c); + + return; +} + +size_t content_html_receive_data(struct content* c, void* data, size_t size, size_t nmemb) +{ + size_t amount = nmemb; + int offset = 0; + size_t numInChunk = 2048 / size; /* process in 2k chunks */ + + if (numInChunk > nmemb) + numInChunk = nmemb; + else if (numInChunk <= (size_t)0) + numInChunk = 1; + + while (amount > 0) + { + htmlParseChunk(c->data.html.parser, (char*)data + (offset * size), numInChunk, 0); + offset += numInChunk; + amount -= numInChunk; + if (amount < numInChunk) + numInChunk = amount; + gui_multitask(); + } + + return size * nmemb; +} + +void set_content_html(struct content* c) +{ + c->type = CONTENT_HTML; + c->data.html.parser = htmlCreatePushParserCtxt(0, 0, "", 0, 0, XML_CHAR_ENCODING_8859_1); + c->data.html.document = NULL; + c->data.html.markup = NULL; + c->data.html.layout = NULL; + c->data.html.stylesheet = NULL; + c->data.html.style = NULL; + return; +} + +void content_html_reformat(struct content* c, int width) +{ + char* file; + struct css_selector* selector = xcalloc(1, sizeof(struct css_selector)); + + Log("content_html_reformat", "Starting stuff"); + c->data.html.layout = NULL; /* should be a freeing operation here */ + /* free other things too... */ + + Log("content_html_reformat", "Setting document to myDoc"); + c->data.html.document = c->data.html.parser->myDoc; + + /* skip to start of html */ + Log("content_html_reformat", "Skipping to html"); + if (c->data.html.document == NULL) + { + Log("content_html_reformat", "There is no document!"); + return; + } + for (c->data.html.markup = c->data.html.document->children; + c->data.html.markup != 0 && + c->data.html.markup->type != XML_ELEMENT_NODE; + c->data.html.markup = c->data.html.markup->next) + ; + + if (c->data.html.markup == 0) + { + Log("content_html_reformat", "No markup"); + return; + } + if (strcmp((const char *) c->data.html.markup->name, "html")) + { + Log("content_html_reformat", "Not html"); + return; + } + + Log("content_html_reformat", "Loading CSS"); + file = load(".Resources.CSS"); /*!!! not portable! !!!*/ + c->data.html.stylesheet = css_new_stylesheet(); + Log("content_html_reformat", "Parsing stylesheet"); + css_parse_stylesheet(c->data.html.stylesheet, file); + + Log("content_html_reformat", "Copying base style"); + c->data.html.style = xcalloc(1, sizeof(struct css_style)); + memcpy(c->data.html.style, &css_base_style, sizeof(struct css_style)); + + Log("content_html_reformat", "Creating box"); + c->data.html.layout = xcalloc(1, sizeof(struct box)); + c->data.html.layout->type = BOX_BLOCK; + c->data.html.layout->node = c->data.html.markup; + + Log("content_html_reformat", "XML to box"); + xml_to_box(c->data.html.markup, c->data.html.style, c->data.html.stylesheet, &selector, 0, c->data.html.layout, 0, 0); + Log("content_html_reformat", "Layout document"); + layout_document(c->data.html.layout->children, (unsigned long)width); + + /* can tidy up memory here? */ + + return; +} + +void browser_window_reformat(struct browser_window* bw) +{ + Log("browser_window_reformat", "Entering..."); + if (bw == NULL) + return; + if (bw->current_content == NULL) + return; + + switch (bw->current_content->type) + { + case CONTENT_HTML: + Log("browser_window_reformat", "HTML content."); + browser_window_set_status(bw, "Formatting page..."); + content_html_reformat(bw->current_content, bw->format_width); + Log("browser_window_reformat", "Content reformatted"); + if (bw->current_content->data.html.layout != NULL) + { + Log("browser_window_reformat", "Setting extent"); + gui_window_set_extent(bw->window, bw->current_content->data.html.layout->children->width, bw->current_content->data.html.layout->children->height); + Log("browser_window_reformat", "Setting scroll"); + gui_window_set_scroll(bw->window, 0, 0); + Log("browser_window_reformat", "Redraw window"); + gui_window_redraw_window(bw->window); + Log("browser_window_reformat", "Complete"); + browser_window_set_status(bw, "Format complete."); + } + else + { + Log("browser_window_reformat", "This isn't html"); + browser_window_set_status(bw, "This is not HTML!"); + content_destroy(bw->current_content); + bw->current_content = NULL; + } + break; + default: + Log("browser_window_reformat", "Unknown content type"); + break; + } +} + +/* create a new history item */ +struct history* history_create(char* desc, char* url) +{ + struct history* h = xcalloc(1, sizeof(struct history)); + h->description = xstrdup(desc); + h->url = xstrdup(url); + return h; +} + +/* remember a new page after the current one. anything remembered after the + current page is forgotten. */ +void history_remember(struct history* current, char* desc, char* url) +{ + struct history* h; + assert(current != NULL); + + /* forget later history items */ + h = current->later; + while (h != NULL) + { + struct history* hh; + hh = h; + h = h->later; + + if (hh->description != NULL) + xfree(hh->description); + if (hh->url != NULL) + xfree(hh->url); + + xfree(hh); + } + + current->later = history_create(desc, url); + return; +} + + +struct browser_window* create_browser_window(int flags, int width, int height) +{ + struct browser_window* bw; + bw = (struct browser_window*) xcalloc(1, sizeof(struct browser_window)); + + bw->flags = flags; + bw->format_width = width; + bw->format_height = height; + + bw->scale.mult = 1; + bw->scale.div = 1; + + bw->current_content = NULL; + bw->future_content = NULL; + bw->history = NULL; + + bw->url = NULL; + bw->title = xstrdup("NetSurf"); + + bw->window = create_gui_browser_window(bw); + + return bw; +} + +void browser_window_set_status(struct browser_window* bw, char* text) +{ + if (bw->window != NULL) + gui_window_set_status(bw->window, text); +} + +void browser_window_destroy(struct browser_window* bw) +{ + if (bw == NULL) + return; + + content_destroy(bw->current_content); + content_destroy(bw->future_content); + + if (bw->history != NULL) + { + struct history* current; + + while (current->earlier != NULL) + current = current->earlier; + + while (current != NULL) + { + struct history* hh; + hh = current; + current = current->later; + + if (hh->description != NULL) + xfree(hh->description); + if (hh->url != NULL) + xfree(hh->url); + + xfree(hh); + } + } + + xfree(bw->url); + xfree(bw->title); + + gui_window_destroy(bw->window); + + xfree(bw); + + return; +} + +void browser_window_open_location(struct browser_window* bw, char* url) +{ + struct fetch_request* req; + + if (bw == NULL) + return; + + if (bw->future_content != NULL) + content_destroy(bw->future_content); + + req = xcalloc(1, sizeof(struct fetch_request)); + req->type = REQUEST_FROM_BROWSER; + req->requestor.browser = bw; + + bw->future_content = (struct content*) xcalloc(1, sizeof(struct content)); + bw->future_content->main_fetch = create_fetch(url, bw->url, 0, req); + + return; +} + +int browser_window_message(struct browser_window* bw, struct browser_message* msg) +{ + gui_safety previous_safety; + + switch (msg->type) + { + case msg_FETCH_SENDING: + browser_window_set_status(bw, "Sending request..."); + break; + + case msg_FETCH_WAITING: + browser_window_set_status(bw, "Waiting for reply..."); + break; + + case msg_FETCH_FETCH_INFO: + browser_window_set_status(bw, "Request received..."); + if (msg->f == bw->future_content->main_fetch) + { + switch (msg->data.fetch_info.type) + { + case type_HTML: + set_content_html(bw->future_content); + break; + default: + return 1; + } + } + break; + + case msg_FETCH_DATA: + browser_window_set_status(bw, "Data received..."); + if (msg->f == bw->future_content->main_fetch) + content_html_receive_data(bw->future_content, msg->data.fetch_data.block, sizeof(char), msg->data.fetch_data.block_size); + break; + + case msg_FETCH_ABORT: + browser_window_set_status(bw, "Request failed."); + if (msg->f == bw->future_content->main_fetch) + { + bw->future_content->main_fetch = NULL; + content_destroy(bw->future_content); + bw->future_content = NULL; + } + break; + + case msg_FETCH_FINISHED: + browser_window_set_status(bw, "Request complete."); + if (msg->f == bw->future_content->main_fetch) + { + struct gui_message gmsg; + if (bw->future_content->main_fetch->location != NULL) + xfree(bw->url); + bw->url = xstrdup(bw->future_content->main_fetch->location); + + gmsg.type = msg_SET_URL; + gmsg.data.set_url.url = bw->url; + gui_window_message(bw->window, &gmsg); + + htmlParseChunk(bw->future_content->data.html.parser, "", 0, 1); + bw->future_content->main_fetch = NULL; + previous_safety = gui_window_set_redraw_safety(bw->window, UNSAFE); + content_destroy(bw->current_content); + bw->current_content = bw->future_content; + bw->future_content = NULL; + browser_window_reformat(bw); + gui_window_set_redraw_safety(bw->window, previous_safety); + } + break; + + default: + browser_window_set_status(bw, "???"); + break; + } + + return 0; +} + +int browser_window_action(struct browser_window* bw, struct browser_action* act) +{ + switch (act->type) + { + case act_MOUSE_AT: + browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 0); + break; + case act_MOUSE_CLICK: + break; + case act_CLEAR_SELECTION: + browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 0); + break; + case act_START_NEW_SELECTION: + browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 1); + break; + case act_ALTER_SELECTION: + browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 2); + break; + case act_FOLLOW_LINK: + browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 1); + break; + case act_FOLLOW_LINK_NEW_WINDOW: + browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 2); + break; + default: + break; + } + return 0; +} + +void box_under_area(struct box* box, int x, int y, int ox, int oy, + struct box_selection** found, int* count, int* plot_index) +{ + struct box* c; + + if (box == NULL) + return; + + *plot_index = *plot_index + 1; + + if (x >= box->x + ox && x <= box->x + ox + box->width && + y >= box->y + oy && y <= box->y + oy + box->height) + { + *found = xrealloc(*found, sizeof(struct box_selection) * (*count + 1)); + (*found)[*count].box = box; + (*found)[*count].actual_x = box->x + ox; + (*found)[*count].actual_y = box->y + oy; + (*found)[*count].plot_index = *plot_index; + *count = *count + 1; + } + + for (c = box->children; c != 0; c = c->next) + if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT) + box_under_area(c, x, y, box->x + ox, box->y + oy, found, count, plot_index); + + for (c = box->float_children; c != 0; c = c->next_float) + box_under_area(c, x, y, box->x + ox, box->y + oy, found, count, plot_index); + + return; +} + +void browser_window_follow_link(struct browser_window* bw, + int click_x, int click_y, int click_type) +{ + struct box_selection* click_boxes; + int found, plot_index; + int i; + int done = 0; + + found = 0; + click_boxes = NULL; + plot_index = 0; + + box_under_area(bw->current_content->data.html.layout->children, + click_x, click_y, 0, 0, &click_boxes, &found, &plot_index); + + if (found == 0) + return; + + for (i = found - 1; i >= 0; i--) + { + if (click_boxes[i].box->href != NULL) + { + if (click_type == 1) + browser_window_open_location(bw, (char*) click_boxes[i].box->href); + else if (click_type == 2) + { + struct browser_window* bw_new; + bw_new = create_browser_window(browser_TITLE | browser_TOOLBAR + | browser_SCROLL_X_NONE | browser_SCROLL_Y_ALWAYS, 640, 480); + gui_window_show(bw_new->window); + if (bw->url != NULL) + bw_new->url = xstrdup(bw->url); + browser_window_open_location(bw_new, (char*) click_boxes[i].box->href); + } + else if (click_type == 0) + { + browser_window_set_status(bw, (char*) click_boxes[i].box->href); + done = 1; + } + i = -1; + } + } + + if (click_type == 0 && done == 0) + browser_window_set_status(bw, ""); + + free(click_boxes); + + return; +} + +void browser_window_text_selection(struct browser_window* bw, + int click_x, int click_y, int click_type) +{ + struct box_selection* click_boxes; + int found, plot_index; + int i; + + if (click_type == 0 /* click_CLEAR_SELECTION */ ) + { + browser_window_clear_text_selection(bw); + return; + } + + found = 0; + click_boxes = NULL; + plot_index = 0; + + box_under_area(bw->current_content->data.html.layout->children, + click_x, click_y, 0, 0, &click_boxes, &found, &plot_index); + + if (found == 0) + return; + + for (i = found - 1; i >= 0; i--) + { + if (click_boxes[i].box->type == BOX_INLINE) + { + struct box_position new_pos; + struct box_position* start; + struct box_position* end; + int click_char_offset, click_pixel_offset; + + /* shortcuts */ + start = &(bw->current_content->data.html.text_selection.start); + end = &(bw->current_content->data.html.text_selection.end); + + font_position_in_string(click_boxes[i].box->text, + click_boxes[i].box->style, click_boxes[i].box->length, + click_x - click_boxes[i].actual_x, + &click_char_offset, &click_pixel_offset); + + new_pos.box = click_boxes[i].box; + new_pos.actual_box_x = click_boxes[i].actual_x; + new_pos.actual_box_y = click_boxes[i].actual_y; + new_pos.plot_index = click_boxes[i].plot_index; + new_pos.char_offset = click_char_offset; + new_pos.pixel_offset = click_pixel_offset; + + if (click_type == 1 /* click_START_SELECTION */ ) + { + /* update both start and end */ + browser_window_clear_text_selection(bw); + bw->current_content->data.html.text_selection.altering = alter_UNKNOWN; + bw->current_content->data.html.text_selection.selected = 1; + memcpy(start, &new_pos, sizeof(struct box_position)); + memcpy(end, &new_pos, sizeof(struct box_position)); + i = -1; + } + else if (bw->current_content->data.html.text_selection.selected == 1 && + click_type == 2 /* click_ALTER_SELECTION */) + { + /* alter selection */ + + if (bw->current_content->data.html.text_selection.altering + != alter_UNKNOWN) + { + if (bw->current_content->data.html.text_selection.altering + == alter_START) + { + if (box_position_gt(&new_pos,end)) + { + bw->current_content->data.html.text_selection.altering + = alter_END; + browser_window_change_text_selection(bw, end, &new_pos); + } + else + browser_window_change_text_selection(bw, &new_pos, end); + } + else + { + if (box_position_lt(&new_pos,start)) + { + bw->current_content->data.html.text_selection.altering + = alter_START; + browser_window_change_text_selection(bw, &new_pos, start); + } + else + browser_window_change_text_selection(bw, start, &new_pos); + } + i = -1; + } + else + { + /* work out whether the start or end is being dragged */ + + int click_start_distance = 0; + int click_end_distance = 0; + + int inside_block = 0; + int before_start = 0; + int after_end = 0; + + if (box_position_lt(&new_pos, start)) + before_start = 1; + + if (box_position_gt(&new_pos, end)) + after_end = 1; + + if (!box_position_lt(&new_pos, start) + && !box_position_gt(&new_pos, end)) + inside_block = 1; + + if (inside_block == 1) + { + click_start_distance = box_position_distance(start, &new_pos); + click_end_distance = box_position_distance(end, &new_pos); + } + + if (before_start == 1 + || (after_end == 0 && inside_block == 1 + && click_start_distance < click_end_distance)) + { + /* alter the start position */ + bw->current_content->data.html.text_selection.altering + = alter_START; + browser_window_change_text_selection(bw, &new_pos, end); + i = -1; + } + else if (after_end == 1 + || (before_start == 0 && inside_block == 1 + && click_start_distance >= click_end_distance)) + { + /* alter the end position */ + bw->current_content->data.html.text_selection.altering = alter_END; + browser_window_change_text_selection(bw, start, &new_pos); + i = -1; + } + } + } + } + } + + free(click_boxes); + + return; +} + +void browser_window_clear_text_selection(struct browser_window* bw) +{ + struct box_position* old_start; + struct box_position* old_end; + + old_start = &(bw->current_content->data.html.text_selection.start); + old_end = &(bw->current_content->data.html.text_selection.end); + + if (bw->current_content->data.html.text_selection.selected == 1) + { + bw->current_content->data.html.text_selection.selected = 0; + browser_window_redraw_boxes(bw, old_start, old_end); + } + + bw->current_content->data.html.text_selection.altering = alter_UNKNOWN; +} + +void browser_window_change_text_selection(struct browser_window* bw, + struct box_position* new_start, struct box_position* new_end) +{ + struct box_position start; + struct box_position end; + + memcpy(&start, &(bw->current_content->data.html.text_selection.start), sizeof(struct box_position)); + memcpy(&end, &(bw->current_content->data.html.text_selection.end), sizeof(struct box_position)); + + if (!box_position_eq(new_start, &start)) + { + if (box_position_lt(new_start, &start)) + browser_window_redraw_boxes(bw, new_start, &start); + else + browser_window_redraw_boxes(bw, &start, new_start); + memcpy(&start, new_start, sizeof(struct box_position)); + } + + if (!box_position_eq(new_end, &end)) + { + if (box_position_lt(new_end, &end)) + browser_window_redraw_boxes(bw, new_end, &end); + else + browser_window_redraw_boxes(bw, &end, new_end); + memcpy(&end, new_end, sizeof(struct box_position)); + } + + memcpy(&(bw->current_content->data.html.text_selection.start), &start, sizeof(struct box_position)); + memcpy(&(bw->current_content->data.html.text_selection.end), &end, sizeof(struct box_position)); + + bw->current_content->data.html.text_selection.selected = 1; +} + + +int box_position_lt(struct box_position* x, struct box_position* y) +{ + return (x->plot_index < y->plot_index || + (x->plot_index == y->plot_index && x->char_offset < y->char_offset)); +} + +int box_position_gt(struct box_position* x, struct box_position* y) +{ + return (x->plot_index > y->plot_index || + (x->plot_index == y->plot_index && x->char_offset > y->char_offset)); +} + +int box_position_eq(struct box_position* x, struct box_position* y) +{ + return (x->plot_index == y->plot_index && x->char_offset == y->char_offset); +} + +int box_position_distance(struct box_position* x, struct box_position* y) +{ + int dx = (y->actual_box_x + y->pixel_offset) + - (x->actual_box_x + x->pixel_offset); + int dy = (y->actual_box_y + y->box->height / 2) + - (x->actual_box_y + x->box->height / 2); + return dx*dx + dy*dy; +} + +int redraw_min_x = INT_MAX; +int redraw_min_y = INT_MAX; +int redraw_max_x = INT_MIN; +int redraw_max_y = INT_MIN; + +int redraw_box_list(struct browser_window* bw, struct box* current, + int x, int y, struct box_position* start, struct box_position* end, + int* plot) +{ + + struct box* c; + + if (current == start->box) + *plot = 1; + + if (*plot >= 1 && current->type == BOX_INLINE) + { + int minx = x + current->x; + int miny = y + current->y; + int maxx = x + current->x + current->width; + int maxy = y + current->y + current->height; + + if (minx < redraw_min_x) + redraw_min_x = minx; + if (miny < redraw_min_y) + redraw_min_y = miny; + if (maxx > redraw_max_x) + redraw_max_x = maxx; + if (maxy > redraw_max_y) + redraw_max_y = maxy; + + *plot = 2; + } + + if (current == end->box) + return 1; + + for (c = current->children; c != 0; c = c->next) + if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT) + if (redraw_box_list(bw, c, x + current->x, y + current->y, + start, end, plot) == 1) + return 1; + + for (c = current->float_children; c != 0; c = c->next_float) + if (redraw_box_list(bw, c, x + current->x, y + current->y, + start, end, plot) == 1) + return 1; + + return 0; +} + +void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end) +{ + int plot = 0; + + if (box_position_eq(start, end)) + return; + + redraw_min_x = INT_MAX; + redraw_min_y = INT_MAX; + redraw_max_x = INT_MIN; + redraw_max_y = INT_MIN; + + redraw_box_list(bw, bw->current_content->data.html.layout, + 0,0, start, end, &plot); + + if (plot == 2) + gui_window_redraw(bw->window, redraw_min_x, redraw_min_y, + redraw_max_x, redraw_max_y); +} diff --git a/desktop/browser.h b/desktop/browser.h new file mode 100644 index 000000000..1e158b3a8 --- /dev/null +++ b/desktop/browser.h @@ -0,0 +1,148 @@ +/** + * $Id: browser.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_DESKTOP_BROWSER_H_ +#define _NETSURF_DESKTOP_BROWSER_H_ + +#include "libxml/HTMLparser.h" +#include "netsurf/render/css.h" +#include "netsurf/render/box.h" +#include "netsurf/desktop/gui.h" +#include "netsurf/desktop/fetch.h" + +typedef int browser_window_flags; +#define browser_TOOLBAR ((browser_window_flags) 1) +#define browser_TITLE ((browser_window_flags) 2) +#define browser_SCROLL_X_NONE ((browser_window_flags) 4) +#define browser_SCROLL_X_AUTO ((browser_window_flags) 8) +#define browser_SCROLL_X_ALWAYS ((browser_window_flags) 16) +#define browser_SCROLL_Y_NONE ((browser_window_flags) 32) +#define browser_SCROLL_Y_AUTO ((browser_window_flags) 64) +#define browser_SCROLL_Y_ALWAYS ((browser_window_flags) 128) + +typedef int action_buttons; +#define act_BUTTON_NORMAL ((action_buttons) 4) +#define act_BUTTON_ALTERNATIVE ((action_buttons) 1) +#define act_BUTTON_CONTEXT_MENU ((action_buttons) 2) + + + +struct box_position +{ + struct box* box; + int actual_box_x; + int actual_box_y; + int plot_index; + int pixel_offset; + int char_offset; +}; + +struct content +{ + enum {CONTENT_UNKNOWN, CONTENT_HTML, CONTENT_IMAGE} type; + + union + { + struct + { + htmlParserCtxt* parser; + xmlDoc* document; + xmlNode* markup; + struct box* layout; + struct css_stylesheet* stylesheet; + struct css_style* style; + struct { + struct box_position start; + struct box_position end; + enum {alter_UNKNOWN, alter_START, alter_END} altering; + int selected; /* 0 = unselected, 1 = selected */ + } text_selection; + } html; + } data; + struct fetch* main_fetch; +}; + + +struct history +{ + struct history* earlier; + struct history* later; + char* description; + char* url; +}; + +struct history* history_create(char* desc, char* url); +void history_remember(struct history* current, char* desc, char* url); + + +struct browser_window +{ + int format_width; + int format_height; + struct { int mult; int div; } scale; + + struct content* current_content; + struct content* future_content; + struct history* history; + + char* url; + + browser_window_flags flags; + char* title; + gui_window* window; +}; + + +struct browser_message +{ + enum { msg_UNKNOWN, + msg_FETCH_SENDING, msg_FETCH_WAITING, msg_FETCH_ABORT, + msg_FETCH_FETCH_INFO, msg_FETCH_DATA, msg_FETCH_FINISHED + } type; + struct fetch* f; + union { + struct { + enum { type_UNKNOWN, type_HTML } type; /* should be a MIME type ? */ + int total_size; /* -1 == unknown size */ + } fetch_info; + struct { + char* block; + int block_size; + } fetch_data; + } data; +}; + + +struct browser_action +{ + enum { act_UNKNOWN, + act_MOUSE_AT, act_MOUSE_CLICK, act_START_NEW_SELECTION, + act_ALTER_SELECTION, act_CLEAR_SELECTION, + act_FOLLOW_LINK, act_FOLLOW_LINK_NEW_WINDOW + } type; + union { + struct { + int x; + int y; + action_buttons buttons; + } mouse; + } data; +}; + +/* public functions */ + +struct browser_window* create_browser_window(int flags, int width, int height); +void browser_window_destroy(struct browser_window* bw); +void browser_window_open_location(struct browser_window* bw, char* url); +int browser_window_message(struct browser_window* bw, struct browser_message* msg); +int browser_window_action(struct browser_window* bw, struct browser_action* act); +void browser_window_set_status(struct browser_window* bw, char* text); + +int box_position_lt(struct box_position* x, struct box_position* y); +int box_position_gt(struct box_position* x, struct box_position* y); +int box_position_eq(struct box_position* x, struct box_position* y); +int box_position_distance(struct box_position* x, struct box_position* y); + + +#endif diff --git a/desktop/fetch.c b/desktop/fetch.c new file mode 100644 index 000000000..a7881fcc2 --- /dev/null +++ b/desktop/fetch.c @@ -0,0 +1,344 @@ +/** + * $Id: fetch.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#include "libxml/HTMLparser.h" +#include "netsurf/render/box.h" +#include "netsurf/render/css.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/netsurf.h" +#include "netsurf/desktop/fetch.h" +#include "netsurf/render/utils.h" +#include "curl/curl.h" +#include +#include +#include + +void fetch_identify_location(struct fetch* f, char* location, char* previous) +{ + FILE* ff = fopen("identify", "a"); + fprintf(ff, "identify: '%s' '%s'", location, previous); + if (f->location != NULL) + fprintf(ff, " '%s'\n", f->location); + else + fprintf(ff, "\n"); + fclose(ff); + + if (f->location != NULL) + xfree(f->location); + + if (strspn(location, "http://") == strlen("http://")) + { + f->location = xstrdup(location); + f->type = fetch_CURL; + return; + } + else if (strspn(location, "file:/") == strlen("file:/")) + { + f->location = xstrdup(location); + f->type = fetch_FILE; + return; + } + else if (previous != NULL) + { + char* ext = strrchr(previous, '/'); + + if (ext != NULL && ext != previous) + { + int len = (int)(ext - previous) + strlen(location) + 2; + char* combined = xcalloc(len, sizeof(char)); + strncpy(combined, previous, (int)(ext - previous)); + strcpy(combined + (ext - previous), "/"); + strcpy(combined + (ext - previous) + 1, location); + fetch_identify_location(f, combined, NULL); + xfree(combined); + return; + } + } + + f->location = xcalloc(strlen(location) + strlen("http://") + 1, sizeof(char)); + sprintf(f->location, "http://%s", location); + f->type = fetch_CURL; + return; +} + +struct fetch* create_fetch(char* location, char* previous, fetch_flags f, struct fetch_request* r) +{ + struct fetch* fetch = (struct fetch*) xcalloc(1, sizeof(struct fetch)); + + fetch_identify_location(fetch, location, previous); + + fetch->flags = f; + + fetch->status = fetch_STATUS_WAIT; + fetch->bytes_fetched = 0; + fetch->bytes_total = -1; + + fetch->request = r; + + fetch->start_time = time(&fetch->start_time); + + fetch->next = netsurf_fetches; + netsurf_fetches = fetch; + + return fetch; +} + +void fetch_destroy(struct fetch* f) +{ + if (f == NULL) + return; + + if (netsurf_fetches == f) + netsurf_fetches = f->next; + else + { + struct fetch* ff = netsurf_fetches; + while (ff->next != f && ff->next != NULL) + ff = ff->next; + if (ff->next == f) + ff->next = f->next; + } + + xfree(f->location); + xfree(f->request); + xfree(f); +} + +struct fetch* fetch_cancel(struct fetch* f) +{ + if (f == NULL) + return NULL; + + /* may need to contact server here */ + + f->status = fetch_DELETED; + /* fetch may not necessarily be destroyed if the cancelling can't be done + instantly */ + return f; +} + +void fetch_receive(struct fetch* f, int amount, char* bytes) +{ + struct browser_message msg; + + f->bytes_fetched = f->bytes_fetched + amount; + + switch (f->request->type) + { + case REQUEST_FROM_BROWSER: + msg.type = msg_FETCH_DATA; + msg.f = f; + msg.data.fetch_data.block = bytes; + msg.data.fetch_data.block_size = amount; + if (browser_window_message(f->request->requestor.browser, &msg) != 0) + { + fetch_cancel(f); + return; + } + break; + default: + break; + } + + if (f->bytes_fetched >= f->bytes_total && f->bytes_total != -1) + { + msg.type = msg_FETCH_FINISHED; + msg.f = f; + browser_window_message(f->request->requestor.browser, &msg); + fetch_destroy(f); + } + + return; +} + +size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch* f) +{ + struct browser_message msg; + msg.type = msg_FETCH_DATA; + msg.f = f; + msg.data.fetch_data.block = data; + msg.data.fetch_data.block_size = size * nmemb; + Log("fetch_poll","sending curl's FETCH_DATA to browser"); + browser_window_message(f->request->requestor.browser, &msg); + return size * nmemb; +} + +struct fetch* fetch_poll(struct fetch* f) +{ + struct fetch* ret = f; + + Log("fetch_poll","polling..."); + + if (f == NULL) + { + Log("fetch_poll","null fetch; returning"); + return f; + } + + if (f->type == fetch_DELETED) + { + ret = f->next; + Log("fetch_poll", "deleting marked fetch"); + fetch_destroy(f); + Log("fetch_poll", "moving on..."); + return fetch_poll(ret); + } + else if (f->type == fetch_CURL && f->status == fetch_STATUS_WAIT) + { + struct browser_message msg; + CURL* curl; + + Log("fetch_poll","init curl"); + curl = curl_easy_init(); + Log("fetch_poll","init curl returned"); + if (curl != 0) + { + Log("fetch_poll","init curl OK"); + /* shouldn't assume this! somehow work it out instead. */ + msg.type = msg_FETCH_FETCH_INFO; + msg.f = f; + msg.data.fetch_info.type = type_HTML; + msg.data.fetch_info.total_size = -1; + + if (browser_window_message(f->request->requestor.browser, &msg) == 0) + { + Log("fetch_poll","about to set options"); + curl_easy_setopt(curl, CURLOPT_URL, f->location); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_curl_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); + Log("fetch_poll","about to perform"); + curl_easy_perform(curl); + Log("fetch_poll","about to cleanup"); + curl_easy_cleanup(curl); + + Log("fetch_poll","cleanup finished"); + msg.type = msg_FETCH_FINISHED; + msg.f = f; + Log("fetch_poll","sending FETCH_FINISHED to browser"); + browser_window_message(f->request->requestor.browser, &msg); + Log("fetch_poll","FETCH_FINISHED accepted"); + + ret = f->next; + Log("fetch_poll","Destroying f"); + fetch_destroy(f); + Log("fetch_poll","Moving on..."); + return fetch_poll(ret); + } + Log("fetch_poll","about to cleanup since requestor went funny"); + curl_easy_cleanup(curl); + + Log("fetch_poll","Requesting browser didn't like something"); + ret = f->next; + Log("fetch_poll","Cancelling fetch"); + f = fetch_cancel(f); + return fetch_poll(ret); + } + + Log("fetch_poll","we are aborting the mission"); + msg.type = msg_FETCH_ABORT; + msg.f = f; + browser_window_message(f->request->requestor.browser, &msg); + Log("fetch_poll","ABORT message sent to browser"); + + ret = f->next; + fetch_destroy(f); + return fetch_poll(ret); /* carry on polling */ + } + else if (f->type == fetch_FILE && f->status == fetch_STATUS_WAIT) + { + struct browser_message msg; + char actual_filename[1024]; + FILE* in; + + gui_file_to_filename(f->location, actual_filename, 1024); + in = fopen("files","a"); + fprintf(in, "%s\n%s\n\n",f->location, actual_filename); + fclose(in); + in = fopen(actual_filename, "r"); + + if (in == NULL) + { + /* can't open file -- send abort to requestor, then destroy */ + Log("fetch_poll","can't open file"); + msg.type = msg_FETCH_ABORT; + msg.f = f; + browser_window_message(f->request->requestor.browser, &msg); + Log("fetch_poll","ABORT message sent to browser"); + + ret = f->next; + fetch_destroy(f); + Log("fetch_poll","destroyed f; moving on"); + + return fetch_poll(ret); /* carry on polling */ + } + else + { + /* file opened successfully. now to send size and type to requestor, + then the data, then finish. */ + int size; + + /* calculate size */ + Log("fetch_poll","calculating file size"); + fseek(in, 0, SEEK_END); + size = (int) ftell(in); + fclose(in); + + /* send file info. (assuming HTML at the mo, but should work out + what it is, somehow) */ + msg.type = msg_FETCH_FETCH_INFO; + msg.f = f; + msg.data.fetch_info.type = type_HTML; + msg.data.fetch_info.total_size = size; + + Log("fetch_poll","sending FETCH_INFO to browser"); + if (browser_window_message(f->request->requestor.browser, &msg) == 0) + { + /* file info accepted. can now load the data and send it */ + Log("fetch_poll","FETCH_INFO accepted"); + f->status = fetch_STATUS_FETCH; + + /* load and send data */ + msg.type = msg_FETCH_DATA; + msg.f = f; + msg.data.fetch_data.block = load(actual_filename); + msg.data.fetch_data.block_size = size; + Log("fetch_poll","sending FETCH_DATA to browser"); + if (browser_window_message(f->request->requestor.browser, &msg) == 0) + { + xfree(msg.data.fetch_data.block); + /* data accepted. no more data, so finish */ + Log("fetch_poll","FETCH_DATA accepted"); + f->status = fetch_STATUS_FINISH; + + /* send finish */ + msg.type = msg_FETCH_FINISHED; + msg.f = f; + Log("fetch_poll","sending FETCH_FINISHED to browser"); + browser_window_message(f->request->requestor.browser, &msg); + Log("fetch_poll","FETCH_FINISHED accepted"); + + ret = f->next; + Log("fetch_poll","Destroying f"); + fetch_destroy(f); + Log("fetch_poll","Moving on..."); + return fetch_poll(ret); + /* destroy this fetch, then move on to next fetch to poll */ + } + xfree(msg.data.fetch_data.block); + } + + /* requestor didn't like something, and wants the fetch cancelled */ + Log("fetch_poll","Requesting browser didn't like something"); + ret = f->next; + Log("fetch_poll","Cancelling fetch"); + f = fetch_cancel(f); + return fetch_poll(ret); + } + } + + Log("fetch_poll","Moving on (at end of function with f->next)"); + f->next = fetch_poll(f->next); + return f; +} + diff --git a/desktop/fetch.h b/desktop/fetch.h new file mode 100644 index 000000000..c0c2c06ac --- /dev/null +++ b/desktop/fetch.h @@ -0,0 +1,49 @@ +/** + * $Id: fetch.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_DESKTOP_FETCH_H_ +#define _NETSURF_DESKTOP_FETCH_H_ + +#include "libxml/HTMLparser.h" +#include "netsurf/render/box.h" +#include "netsurf/render/css.h" +#include "netsurf/desktop/browser.h" +#include + +typedef enum {fetch_FILE, fetch_CURL} fetch_type; +typedef enum {fetch_STATUS_SEND, fetch_STATUS_WAIT, fetch_STATUS_FETCH, fetch_STATUS_FINISH, fetch_DELETED} fetch_status; + +typedef int fetch_flags; +#define fetch_DO_NOT_CHECK_CACHE ((fetch_flags) 1); +#define fetch_DO_NOT_STORE_IN_CACHE ((fetch_flags) 2); + +struct fetch_request { + enum {REQUEST_FROM_BROWSER} type; + union {struct browser_window* browser;} requestor; +}; + +struct fetch +{ + char* location; + fetch_type type; + fetch_flags flags; + + fetch_status status; + int bytes_fetched; + int bytes_total; + + struct fetch_request* request; + + time_t start_time; + + struct fetch* next; +}; + +struct fetch* create_fetch(char* location, char* previous, fetch_flags f, struct fetch_request* r); +void fetch_destroy(struct fetch* f); +struct fetch* fetch_cancel(struct fetch* f); +void fetch_receive(struct fetch* f, int amount, char* bytes); +struct fetch* fetch_poll(struct fetch* f); + +#endif diff --git a/desktop/gui.h b/desktop/gui.h new file mode 100644 index 000000000..5d5607065 --- /dev/null +++ b/desktop/gui.h @@ -0,0 +1,45 @@ +/** + * $Id: gui.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_DESKTOP_GUI_H_ +#define _NETSURF_DESKTOP_GUI_H_ + +typedef enum { GUI_BROWSER_WINDOW } gui_window_type; +typedef enum { SAFE, UNSAFE } gui_safety; + +#include "netsurf/riscos/gui.h" +#include "netsurf/desktop/browser.h" + +struct gui_message +{ + enum { msg_SET_URL } type; + union { + struct { + char* url; + } set_url; + } data; +}; + +typedef struct gui_message gui_message; + +gui_window* create_gui_browser_window(struct browser_window* bw); +void gui_window_destroy(gui_window* g); +void gui_window_show(gui_window* g); +void gui_window_hide(gui_window* g); +void gui_window_redraw(gui_window* g, int x0, int y0, int x1, int y1); +void gui_window_redraw_window(gui_window* g); +void gui_window_set_scroll(gui_window* g, int sx, int sy); +void gui_window_set_extent(gui_window* g, int width, int height); +void gui_window_set_status(gui_window* g, char* text); + +void gui_window_message(gui_window* g, gui_message* msg); + +void gui_init(int argc, char** argv); +void gui_multitask(void); +void gui_poll(void); + +gui_safety gui_window_set_redraw_safety(gui_window* g, gui_safety s); +int gui_file_to_filename(char* location, char* actual_filename, int size); + +#endif diff --git a/desktop/netsurf.c b/desktop/netsurf.c new file mode 100644 index 000000000..cc53acc05 --- /dev/null +++ b/desktop/netsurf.c @@ -0,0 +1,50 @@ +/** + * $Id: netsurf.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#include "netsurf/desktop/netsurf.h" +#include "netsurf/desktop/fetch.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/gui.h" +#include + +int netsurf_quit = 0; +gui_window* netsurf_gui_windows = NULL; +struct fetch* netsurf_fetches = NULL; + + +void netsurf_poll(void) +{ + gui_poll(); + netsurf_fetches = fetch_poll(netsurf_fetches); +} + + +void netsurf_init(int argc, char** argv) +{ + gui_init(argc, argv); +} + + +int main(int argc, char** argv) +{ + netsurf_init(argc, argv); + + while (netsurf_quit == 0) + netsurf_poll(); + + return 0; +} + + +void Log(char* func, char* msg) +{ +#ifdef NETSURF_DUMP + FILE* logfile = NULL; + logfile = fopen("logfile","a"); + if (logfile == NULL) + die("can't open logfile"); + fprintf(logfile, "%s: %s\n", func, msg); + fclose(logfile); +#endif +} diff --git a/desktop/netsurf.h b/desktop/netsurf.h new file mode 100644 index 000000000..1ebdf9d88 --- /dev/null +++ b/desktop/netsurf.h @@ -0,0 +1,35 @@ +/** + * $Id: netsurf.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_DESKTOP_NETSURF_H_ +#define _NETSURF_DESKTOP_NETSURF_H_ + +#include "netsurf/desktop/fetch.h" +#include "netsurf/desktop/browser.h" + +extern struct fetch* netsurf_fetches; +extern gui_window* netsurf_gui_windows; + +extern int netsurf_quit; + +void netsurf_poll(void); +void Log(char* func, char* msg); + +#endif + +#ifndef _NETSURF_DESKTOP_NETSURF_H_ +#define _NETSURF_DESKTOP_NETSURF_H_ + +#include "netsurf/desktop/fetch.h" +#include "netsurf/desktop/browser.h" + +extern struct fetch* netsurf_fetches; +extern gui_window* netsurf_gui_windows; + +extern int netsurf_quit; + +void netsurf_poll(void); +void Log(char* func, char* msg); + +#endif diff --git a/makefile b/makefile index 489135a5b..c9f1de94f 100644 --- a/makefile +++ b/makefile @@ -1,21 +1,24 @@ -# $Id: makefile,v 1.1 2002/07/27 21:10:45 bursa Exp $ +# $Id: makefile,v 1.2 2002/09/11 14:24:02 monkeyson Exp $ all: netsurf,ff8 clean: rm */objs-riscos/* -FLAGS = -g -Wall -W -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual \ +FLAGS = -g -Wall -W -Wundef -Wpointer-arith -Wbad-function-cast -Wcast-qual \ -Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -std=c9x \ -I.. -I../../Tools/libxml2/include -I../../Tools/oslib \ - -I../../Tools/curl/include -Dfd_set=long + -I../../Tools/curl/include -Dfd_set=long -mpoke-function-name CC = riscos-gcc OBJECTS = render/objs-riscos/utils.o render/objs-riscos/css.o \ render/objs-riscos/css_enum.o render/objs-riscos/box.o \ render/objs-riscos/layout.o \ - riscos/objs-riscos/netsurf.o riscos/objs-riscos/font.o -HEADERS = render/box.h render/css.h render/css_enum.h render/font.h \ - render/layout.h render/utils.h + riscos/objs-riscos/gui.o riscos/objs-riscos/font.o \ + desktop/objs-riscos/browser.o desktop/objs-riscos/fetch.o \ + desktop/objs-riscos/netsurf.o +HEADERS = render/box.h render/css.h render/css_enum.h \ + render/layout.h render/utils.h riscos/font.h riscos/gui.h \ + desktop/browser.h desktop/fetch.h desktop/gui.h desktop/netsurf.h LIBS = ../../Tools/libxml2/libxml.ro ../../Tools/oslib/oslib.o ../../Tools/curl/libcurl.ro netsurf,ff8: $(OBJECTS) @@ -29,3 +32,7 @@ render/objs-riscos/%.o: render/%.c $(HEADERS) riscos/objs-riscos/%.o: riscos/%.c $(HEADERS) $(CC) $(FLAGS) -o $@ -c $< + +desktop/objs-riscos/%.o: desktop/%.c $(HEADERS) + $(CC) $(FLAGS) -o $@ -c $< + diff --git a/render/box.c b/render/box.c index 94c550c69..ee9f5b1b4 100644 --- a/render/box.c +++ b/render/box.c @@ -1,5 +1,5 @@ /** - * $Id: box.c,v 1.12 2002/09/08 18:11:56 bursa Exp $ + * $Id: box.c,v 1.13 2002/09/11 14:24:02 monkeyson Exp $ */ #include @@ -113,6 +113,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, xmlNode * c; char * s; + gui_multitask(); + if (n->type == XML_ELEMENT_NODE) { /* work out the style for this element */ *selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector)); diff --git a/render/layout.c b/render/layout.c index 7d15fb11b..53f4eedea 100644 --- a/render/layout.c +++ b/render/layout.c @@ -1,5 +1,5 @@ /** - * $Id: layout.c,v 1.14 2002/09/08 18:11:56 bursa Exp $ + * $Id: layout.c,v 1.15 2002/09/11 14:24:02 monkeyson Exp $ */ #include @@ -86,6 +86,8 @@ void layout_node(struct box * box, unsigned long width, struct box * cont, box, width, cont, cx, cy); #endif + gui_multitask(); + switch (box->type) { case BOX_BLOCK: layout_block(box, width, cont, cx, cy); diff --git a/riscos/font.c b/riscos/font.c index a12ff2241..05faf50cf 100644 --- a/riscos/font.c +++ b/riscos/font.c @@ -1,31 +1,56 @@ /** - * $Id: font.c,v 1.1 2002/07/27 21:10:45 bursa Exp $ + * $Id: font.c,v 1.2 2002/09/11 14:24:02 monkeyson Exp $ */ #include #include "netsurf/render/css.h" #include "netsurf/render/font.h" #include "netsurf/render/utils.h" +#include "netsurf/desktop/gui.h" #include "oslib/font.h" /** * functions */ -extern font_f font; +/** it is rather inefficient calling this all the time **/ +font_f riscos_font_css_to_handle(struct css_style* style) +{ + int width = 12 * 16; + int height = 12 * 16; + char font_name[255]; + + if (style->font_size.size == CSS_FONT_SIZE_LENGTH) + width = height = style->font_size.value.length.value * 16; + + strcpy(font_name, "Homerton."); + if (style->font_weight == CSS_FONT_WEIGHT_BOLD) + strcat(font_name, "Bold"); + else + strcat(font_name, "Medium"); + + if (style->font_style == CSS_FONT_STYLE_ITALIC || style->font_style == CSS_FONT_STYLE_OBLIQUE) + strcat(font_name, ".Oblique"); + + return font_find_font(font_name, width, height, 0, 0, 0, 0); +} unsigned long font_width(struct css_style * style, const char * text, unsigned int length) { font_scan_block block; os_error * error; + font_f font; - if (length == 0) return 0; + if (length == 0) + return 0; block.space.x = block.space.y = 0; block.letter.x = block.letter.y = 0; block.split_char = -1; - error = xfont_scan_string(font, text, + font = riscos_font_css_to_handle(style); + + error = xfont_scan_string(font, (char*) text, font_GIVEN_BLOCK | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | font_RETURN_BBOX, 0x7fffffff, 0x7fffffff, &block, @@ -35,6 +60,59 @@ unsigned long font_width(struct css_style * style, const char * text, unsigned i fprintf(stderr, "%s\n", error->errmess); die("font_scan_string failed"); } + +// fprintf(stderr, "Stated length %d, strlen %d\n", (int)length, strlen(text)); + + if (length < 0x7fffffff) + { + if (text[length - 1] == ' ') +// { + block.bbox.x1 += 4*800; +/* int minx,miny,maxx,maxy; + char space = ' '; +// fprintf(stderr, "Space at the end!\n"); + error = xfont_char_bbox(font, space, 0, &minx, &miny, &maxx, &maxy); + if (error != 0) { + fprintf(stderr, "%s\n", error->errmess); + die("font_char_bbox failed"); + } + block.bbox.x1 += maxx; + } +// else +// fprintf(stderr, "No space\n");*/ + } + + font_lose_font(font); + return block.bbox.x1 / 800; } +void font_position_in_string(const char* text, struct css_style* style, int length, int x, int* char_offset, int* pixel_offset) +{ + font_f font; + font_scan_block block; + char* split_point; + int x_out, y_out, length_out; + + block.space.x = block.space.y = 0; + block.letter.x = block.letter.y = 0; + block.split_char = -1; + + font = riscos_font_css_to_handle(style); + + xfont_scan_string(font, (char*) text, + font_GIVEN_BLOCK | font_GIVEN_LENGTH | + font_GIVEN_FONT | font_KERN | font_RETURN_CARET_POS, + ro_x_units(x) * 400, + 0x7fffffff, + &block, 0, length, + &split_point, &x_out, &y_out, &length_out); + + font_lose_font(font); + + *char_offset = (int)(split_point - text); + *pixel_offset = browser_x_units(x_out / 400); + + return; +} + diff --git a/riscos/font.h b/riscos/font.h new file mode 100644 index 000000000..ee3e4c2b2 --- /dev/null +++ b/riscos/font.h @@ -0,0 +1,39 @@ +/** + * $Id: font.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_RISCOS_FONT_H_ +#define _NETSURF_RISCOS_FONT_H_ + +/** + * structures and typedefs + */ + +#include "netsurf/render/css.h" +#include "oslib/font.h" + +struct font_set; +typedef unsigned int font_id; +struct font_split { + unsigned long width; + unsigned long height; + const char * end; +}; + +/** + * interface + */ + +struct font_set * font_set_create(void); +font_id font_add(struct font_set * font_set, const char * name, unsigned int weight, + unsigned int size); +void font_set_free(struct font_set * font_set); +struct font_split font_split(struct font_set * font_set, font_id id, const char * text, + unsigned long width, int force); +unsigned long font_width(struct css_style * style, const char * text, unsigned int length); + +font_f riscos_font_css_to_handle(struct css_style* style); + +void font_position_in_string(const char* text, struct css_style* style, int length, int x, int* char_offset, int* pixel_offset); + +#endif diff --git a/riscos/gui.c b/riscos/gui.c new file mode 100644 index 000000000..15d38b540 --- /dev/null +++ b/riscos/gui.c @@ -0,0 +1,1057 @@ +/** + * $Id: gui.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#include "netsurf/riscos/font.h" +#include "netsurf/desktop/gui.h" +#include "netsurf/render/utils.h" +#include "netsurf/desktop/netsurf.h" +#include "oslib/wimp.h" +#include "oslib/colourtrans.h" +#include +#include + +#define TOOLBAR_HEIGHT 128; + +char* BROWSER_VALIDATION = "\0"; + +const char* task_name = "NetSurf"; +const wimp_MESSAGE_LIST(1) task_messages = { {0} }; +wimp_t task_handle; + +wimp_i ro_gui_iconbar_i; + +gui_window* over_window = NULL; + +int ro_x_units(int browser_units) +{ + return (browser_units << 1); +} + +int ro_y_units(int browser_units) +{ + return -(browser_units << 1); +} + +int browser_x_units(int ro_units) +{ + return (ro_units >> 1); +} + +int browser_y_units(int ro_units) +{ + return -(ro_units >> 1); +} + +int window_x_units(int scr_units, wimp_window_state* win) +{ + return scr_units - (win->visible.x0 - win->xscroll); +} + +int window_y_units(int scr_units, wimp_window_state* win) +{ + return scr_units - (win->visible.y1 - win->yscroll); +} + +gui_window* create_gui_browser_window(struct browser_window* bw) +{ + struct wimp_window window; + + gui_window* g = (gui_window*) xcalloc(1, sizeof(gui_window)); + g->type = GUI_BROWSER_WINDOW; + g->data.browser.bw = bw; + /* create browser and toolbar windows here */ + + window.visible.x0 = 0; + window.visible.y0 = 0; + window.visible.x1 = ro_x_units(bw->format_width); + window.visible.y1 = 2000; + window.xscroll = 0; + window.yscroll = 0; + window.next = wimp_TOP; + window.flags = + wimp_WINDOW_MOVEABLE | wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_BACK_ICON | + wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_TITLE_ICON | wimp_WINDOW_VSCROLL | + wimp_WINDOW_SIZE_ICON | wimp_WINDOW_TOGGLE_ICON; + window.title_fg = wimp_COLOUR_BLACK; + window.title_bg = wimp_COLOUR_LIGHT_GREY; + window.work_fg = wimp_COLOUR_LIGHT_GREY; + window.work_bg = wimp_COLOUR_WHITE; + window.scroll_outer = wimp_COLOUR_DARK_GREY; + window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY; + window.highlight_bg = wimp_COLOUR_CREAM; + window.extra_flags = 0; + window.extent.x0 = 0; + window.extent.y0 = ro_y_units(bw->format_height); + window.extent.x1 = ro_x_units(bw->format_width); + if ((bw->flags & browser_TOOLBAR) != 0) + { + window.extent.y1 = TOOLBAR_HEIGHT; + } + else + { + window.extent.y1 = 0; + } + window.title_flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED; + window.work_flags = wimp_BUTTON_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT; + window.sprite_area = NULL; + window.xmin = 0; + window.ymin = 2; + window.title_data.indirected_text.text = g->title; + window.title_data.indirected_text.validation = BROWSER_VALIDATION; + window.title_data.indirected_text.size = 255; + window.icon_count = 0; + g->data.browser.window = wimp_create_window(&window); + + strcpy(g->title, "NetSurf"); + + if ((bw->flags & browser_TOOLBAR) != 0) + { + struct wimp_window toolbar; + wimp_icon_create status_icon; + wimp_icon_create url_icon; + + toolbar.visible.x0 = 0; + toolbar.visible.y0 = 0; + toolbar.visible.x1 = 4096; + toolbar.visible.y1 = TOOLBAR_HEIGHT; + toolbar.xscroll = 0; + toolbar.yscroll = 0; + toolbar.next = wimp_TOP; + toolbar.flags = + wimp_WINDOW_MOVEABLE | wimp_WINDOW_NEW_FORMAT | + wimp_WINDOW_AUTO_REDRAW | wimp_WINDOW_FURNITURE_WINDOW; + toolbar.title_fg = wimp_COLOUR_BLACK; + toolbar.title_bg = wimp_COLOUR_LIGHT_GREY; + toolbar.work_fg = wimp_COLOUR_LIGHT_GREY; + toolbar.work_bg = wimp_COLOUR_VERY_LIGHT_GREY; + toolbar.scroll_outer = wimp_COLOUR_DARK_GREY; + toolbar.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY; + toolbar.highlight_bg = wimp_COLOUR_CREAM; + toolbar.extra_flags = 0; + toolbar.extent.x0 = 0; + toolbar.extent.y0 = -TOOLBAR_HEIGHT; + toolbar.extent.x1 = 4096; + if ((bw->flags & browser_TOOLBAR) != 0) + { + toolbar.extent.y1 = TOOLBAR_HEIGHT; + } + else + { + toolbar.extent.y1 = 0; + } + toolbar.title_flags = wimp_ICON_TEXT; + toolbar.work_flags = wimp_BUTTON_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT; + toolbar.sprite_area = NULL; + toolbar.xmin = 0; + toolbar.ymin = 2; + toolbar.icon_count = 0; + g->data.browser.toolbar = wimp_create_window(&toolbar); + + status_icon.w = g->data.browser.toolbar; + status_icon.icon.extent.x0 = 0; + status_icon.icon.extent.y0 = -128; + status_icon.icon.extent.x1 = 4096; + status_icon.icon.extent.y1 = -64; + status_icon.icon.flags = + wimp_ICON_TEXT | wimp_ICON_BORDER | wimp_ICON_VCENTRED | + wimp_ICON_INDIRECTED | wimp_ICON_FILLED | + (wimp_BUTTON_NEVER << wimp_ICON_BUTTON_TYPE_SHIFT) | + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT); + status_icon.icon.data.indirected_text.text = g->status; + status_icon.icon.data.indirected_text.validation = "R2;"; + status_icon.icon.data.indirected_text.size = 255; + wimp_create_icon(&status_icon); + + url_icon.w = g->data.browser.toolbar; + url_icon.icon.extent.x0 = 0; + url_icon.icon.extent.y0 = -64; + url_icon.icon.extent.x1 = 4096; + url_icon.icon.extent.y1 = 0; + url_icon.icon.flags = + wimp_ICON_TEXT | wimp_ICON_BORDER | wimp_ICON_VCENTRED | + wimp_ICON_INDIRECTED | wimp_ICON_FILLED | + (wimp_BUTTON_WRITE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT) | + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); + url_icon.icon.data.indirected_text.text = g->url; + url_icon.icon.data.indirected_text.validation = "Pptr_write;"; + url_icon.icon.data.indirected_text.size = 255; + wimp_create_icon(&url_icon); + } + + g->redraw_safety = SAFE; + + g->next = netsurf_gui_windows; + netsurf_gui_windows = g; + return g; +} + +void gui_window_destroy(gui_window* g) +{ + if (g == NULL) + return; + + if (g == netsurf_gui_windows) + netsurf_gui_windows = g->next; + else + { + gui_window* gg; + gg = netsurf_gui_windows; + while (gg->next != g && gg->next != NULL) + gg = gg->next; + if (gg->next == g) + gg->next = g->next; + } + xfree(g); +} + +void gui_window_show(gui_window* g) +{ + wimp_window_state state; + if (g == NULL) + return; + state.w = g->data.browser.window; + wimp_get_window_state(&state); + state.next = wimp_TOP; + ro_gui_window_open(g, (wimp_open*)&state); +} + +void gui_window_hide(gui_window* g) +{ + if (g == NULL) + return; + wimp_close_window(g->data.browser.window); +} + +void gui_window_redraw(gui_window* g, int x0, int y0, int x1, int y1) +{ + if (g == NULL) + return; + + wimp_force_redraw(g->data.browser.window, + ro_x_units(x0), ro_y_units(y1), ro_x_units(x1), ro_y_units(y0)); +} + +void gui_window_redraw_window(gui_window* g) +{ + wimp_window_info info; + if (g == NULL) + return; + info.w = g->data.browser.window; + wimp_get_window_info_header_only(&info); + wimp_force_redraw(g->data.browser.window, info.extent.x0, info.extent.y0, info.extent.x1, info.extent.y1); +} + +gui_safety gui_window_set_redraw_safety(gui_window* g, gui_safety s) +{ + gui_safety old; + + if (g == NULL) + return SAFE; + + old = g->redraw_safety; + g->redraw_safety = s; + + return old; +} + +int select_on = 0; + +void ro_gui_window_redraw_box(gui_window* g, struct box * box, signed long x, signed long y, os_box* clip) +{ + struct box * c; + const char * const noname = ""; + const char * name = noname; + font_f font; + + switch (box->type) + { + case BOX_TABLE: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + case BOX_BLOCK: if (box->node) name = (const char *) box->node->name; + break; + case BOX_INLINE: + case BOX_INLINE_CONTAINER: + default: + break; + } + + if (x + box->x*2 + box->width*2 /* right edge */ >= clip->x0 && + x + box->x*2 /* left edge */ <= clip->x1 && + y - box->y*2 - box->height*2 - 8 /* bottom edge */ <= clip->y1 && + y - box->y*2 /* top edge */ >= clip->y0) + { + +#ifdef FANCY_LINKS + if (box == g->link_box) + { + colourtrans_set_gcol(os_COLOUR_BLACK, 0, os_ACTION_OVERWRITE, 0); + os_plot(os_MOVE_TO, x + box->x * 2, y - box->y * 2 - box->height * 2 - 4); + os_plot(os_PLOT_SOLID | os_PLOT_BY, box->width * 2, 0); + } +#endif + + if (box->type == BOX_INLINE) + { + + font = riscos_font_css_to_handle(box->style); + +if (g->data.browser.bw->current_content->data.html.text_selection.selected == 1) +{ + struct box_position* start; + struct box_position* end; + + start = &(g->data.browser.bw->current_content->data.html.text_selection.start); + end = &(g->data.browser.bw->current_content->data.html.text_selection.end); + + if (start->box == box) + { + if (end->box == box) + { + colourtrans_set_gcol(os_COLOUR_VERY_LIGHT_GREY, colourtrans_SET_FG, 0, 0); + os_plot(os_MOVE_TO, + x + box->x * 2 + start->pixel_offset * 2, + y - box->y * 2 - box->height * 2); + os_plot(os_PLOT_RECTANGLE | os_PLOT_TO, + x + box->x * 2 + end->pixel_offset * 2 - 2, + y - box->y * 2 - 2); + } + else + { + colourtrans_set_gcol(os_COLOUR_VERY_LIGHT_GREY, colourtrans_SET_FG, 0, 0); + os_plot(os_MOVE_TO, + x + box->x * 2 + start->pixel_offset * 2, + y - box->y * 2 - box->height * 2); + os_plot(os_PLOT_RECTANGLE | os_PLOT_TO, + x + box->x * 2 + box->width * 2 - 2, + y - box->y * 2 - 2); + select_on = 1; + } + } + else if (select_on == 1) + { + if (end->box != box) + { + colourtrans_set_gcol(os_COLOUR_VERY_LIGHT_GREY, colourtrans_SET_FG, 0, 0); + os_plot(os_MOVE_TO, + x + box->x * 2, + y - box->y * 2 - box->height * 2); + os_plot(os_PLOT_RECTANGLE | os_PLOT_TO, + x + box->x * 2 + box->width * 2 - 2, + y - box->y * 2 - 2); + } + else + { + colourtrans_set_gcol(os_COLOUR_VERY_LIGHT_GREY, colourtrans_SET_FG, 0, 0); + os_plot(os_MOVE_TO, + x + box->x * 2, + y - box->y * 2 - box->height * 2); + os_plot(os_PLOT_RECTANGLE | os_PLOT_TO, + x + box->x * 2 + end->pixel_offset * 2 - 2, + y - box->y * 2 - 2); + select_on = 0; + } + } +} + + font_paint(font, (char*) box->text, + font_OS_UNITS | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN, + x + box->x * 2, y - box->y * 2 - box->height * 2, + NULL, NULL, + box->length); + + font_lose_font(font); + + } + } + else + { + if (g->data.browser.bw->current_content->data.html.text_selection.selected == 1) + { + struct box_position* start; + struct box_position* end; + + start = &(g->data.browser.bw->current_content->data.html.text_selection.start); + end = &(g->data.browser.bw->current_content->data.html.text_selection.end); + + if (start->box == box && end->box != box) + select_on = 1; + else if (select_on == 1 && end->box == box) + select_on = 0; + } + } + + for (c = box->children; c != 0; c = c->next) + if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT) + ro_gui_window_redraw_box(g, c, x + box->x * 2, y - box->y * 2, clip); + + for (c = box->float_children; c != 0; c = c->next_float) + ro_gui_window_redraw_box(g, c, x + box->x * 2, y - box->y * 2, clip); +} + + +void ro_gui_window_redraw(gui_window* g, wimp_draw* redraw) +{ + osbool more; + + if (g->redraw_safety == SAFE && g->type == GUI_BROWSER_WINDOW) + { + if (g->data.browser.bw->current_content != NULL) + { + if (g->data.browser.bw->current_content->data.html.layout != NULL) + { + more = wimp_redraw_window(redraw); + wimp_set_font_colours(wimp_COLOUR_WHITE, wimp_COLOUR_BLACK); + + select_on = 0; + + while (more) + { + ro_gui_window_redraw_box(g, + g->data.browser.bw->current_content->data.html.layout->children, + redraw->box.x0 - redraw->xscroll, redraw->box.y1 - redraw->yscroll, + &redraw->clip); + more = wimp_get_rectangle(redraw); + } + return; + } + } + } + + more = wimp_redraw_window(redraw); + while (more) + more = wimp_get_rectangle(redraw); +} + +void gui_window_set_scroll(gui_window* g, int sx, int sy) +{ + wimp_window_state state; + if (g == NULL) + return; + state.w = g->data.browser.window; + wimp_get_window_state(&state); + state.xscroll = ro_x_units(sx); + state.yscroll = ro_y_units(sy); + if ((g->data.browser.bw->flags & browser_TOOLBAR) != 0) + state.yscroll += TOOLBAR_HEIGHT; + ro_gui_window_open(g, (wimp_open*)&state); +} + +void gui_window_set_extent(gui_window* g, int width, int height) +{ + os_box extent; + + if (g == 0) + return; + + extent.x0 = 0; + extent.y0 = ro_y_units(height); + if (extent.y0 > -960) + extent.y0 = -960; + extent.x1 = ro_x_units(width); + if ((g->data.browser.bw->flags & browser_TOOLBAR) != 0) + { + extent.y1 = TOOLBAR_HEIGHT; + } + else + { + extent.y1 = 0; + } + wimp_set_extent(g->data.browser.window, &extent); + +} + +void gui_window_set_status(gui_window* g, char* text) +{ + if (strcmp(g->status, text) != 0) + { + strncpy(g->status, text, 255); + wimp_set_icon_state(g->data.browser.toolbar, 0, 0, 0); + } +} + +void gui_window_message(gui_window* g, gui_message* msg) +{ + if (g == NULL || msg == NULL) + return; + + switch (msg->type) + { + case msg_SET_URL: + strncpy(g->url, msg->data.set_url.url, 255); + wimp_set_icon_state(g->data.browser.toolbar, 1, 0, 0); + break; + default: + break; + } +} + +void ro_gui_window_open(gui_window* g, wimp_open* open) +{ + wimp_open_window(open); + + if (g->type == GUI_BROWSER_WINDOW) + { + if ((g->data.browser.bw->flags & browser_TOOLBAR) != 0) + { + wimp_outline outline; + wimp_window_state tstate; + + outline.w = g->data.browser.window; + wimp_get_window_outline(&outline); + + tstate.w = g->data.browser.toolbar; + tstate.visible.x0 = open->visible.x0; + tstate.visible.x1 = outline.outline.x1 - 2; + tstate.visible.y1 = open->visible.y1; + tstate.visible.y0 = tstate.visible.y1 - TOOLBAR_HEIGHT; + tstate.xscroll = 0; + tstate.yscroll = 0; + tstate.next = wimp_TOP; + + wimp_open_window_nested((wimp_open *) &tstate, g->data.browser.window, + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_LS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_BS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_RS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT + << wimp_CHILD_TS_EDGE_SHIFT); + } + } +} + +void ro_gui_icon_bar_click(wimp_pointer* pointer) +{ + if (pointer->buttons == wimp_CLICK_SELECT) + { + struct browser_window* bw; + bw = create_browser_window(browser_TITLE | browser_TOOLBAR + | browser_SCROLL_X_NONE | browser_SCROLL_Y_ALWAYS, 640, 480); + gui_window_show(bw->window); + browser_window_open_location(bw, "file://Resources/intro.html"); + wimp_set_caret_position(bw->window->data.browser.toolbar, 1, + 0,0,-1, strlen(bw->window->url)); + } + else if (pointer->buttons == wimp_CLICK_ADJUST) + netsurf_quit = 1; +} + + +/*** bodge to fix filenames in unixlib. there's probably a proper way + of doing this, but 'ck knows what it is. ***/ +extern int __riscosify_control; +#define __RISCOSIFY_NO_PROCESS 0x0040 + +void gui_init(int argc, char** argv) +{ + wimp_icon_create iconbar; + wimp_version_no version; + + __riscosify_control = __RISCOSIFY_NO_PROCESS; + + task_handle = wimp_initialise(wimp_VERSION_RO38, task_name, (wimp_message_list*) &task_messages, &version); + + iconbar.w = wimp_ICON_BAR_RIGHT; + iconbar.icon.extent.x0 = 0; + iconbar.icon.extent.y0 = 0; + iconbar.icon.extent.x1 = 68; + iconbar.icon.extent.y1 = 68; + iconbar.icon.flags = wimp_ICON_SPRITE | wimp_ICON_HCENTRED + | wimp_ICON_VCENTRED | (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT); + strcpy(iconbar.icon.data.sprite, "!netsurf"); + ro_gui_iconbar_i = wimp_create_icon(&iconbar); +} + +gui_window* ro_lookup_gui_from_w(wimp_w window) +{ + gui_window* g = netsurf_gui_windows; + while (g != NULL) + { + if (g->type == GUI_BROWSER_WINDOW) + { + if (g->data.browser.window == window) + return g; + } + g = g->next; + } + return NULL; +} + +gui_window* ro_lookup_gui_toolbar_from_w(wimp_w window) +{ + gui_window* g = netsurf_gui_windows; + while (g != NULL) + { + if (g->type == GUI_BROWSER_WINDOW) + { + if (g->data.browser.toolbar == window) + return g; + } + g = g->next; + } + return NULL; +} + + +struct ro_gui_drag_info +{ + enum { draginfo_UNKNOWN, draginfo_NONE, draginfo_BROWSER_TEXT_SELECTION } type; + union + { + struct + { + gui_window* gui; + } selection; + } data; +}; + +struct ro_gui_drag_info current_drag; + +void ro_gui_drag_box(wimp_drag* drag, struct ro_gui_drag_info* drag_info) +{ + wimp_drag_box(drag); + + if (drag_info != NULL) + memcpy(¤t_drag, drag_info, sizeof(struct ro_gui_drag_info)); + else + current_drag.type = draginfo_NONE; +} + +void ro_gui_drag_end(wimp_dragged* drag) +{ + if (current_drag.type == draginfo_BROWSER_TEXT_SELECTION) + { + struct browser_action msg; + int final_x0, final_y0; + wimp_window_state state; + + state.w = current_drag.data.selection.gui->data.browser.window; + wimp_get_window_state(&state); + + final_x0 = browser_x_units(window_x_units(drag->final.x0, &state)); + final_y0 = browser_y_units(window_y_units(drag->final.y0, &state)); + + msg.data.mouse.x = final_x0; + msg.data.mouse.y = final_y0; + msg.type = act_ALTER_SELECTION; + browser_window_action(current_drag.data.selection.gui->data.browser.bw, &msg); + + if (box_position_eq(&(current_drag.data.selection.gui->data.browser.bw->current_content->data.html.text_selection.start), + &(current_drag.data.selection.gui->data.browser.bw->current_content->data.html.text_selection.end))) + { + msg.type = act_CLEAR_SELECTION; + browser_window_action(current_drag.data.selection.gui->data.browser.bw, &msg); + } + current_drag.data.selection.gui->drag_status = drag_NONE; + current_drag.data.selection.gui->data.browser.bw->current_content->data.html.text_selection.altering = alter_UNKNOWN; + } + + current_drag.type = draginfo_NONE; +} + +void ro_gui_window_mouse_at(wimp_pointer* pointer) +{ + int x,y; + wimp_window_state state; + gui_window* g; + + g = ro_lookup_gui_from_w(pointer->w); + + if (g == NULL) + return; + + state.w = pointer->w; + wimp_get_window_state(&state); + + x = browser_x_units(window_x_units(pointer->pos.x, &state)); + y = browser_y_units(window_y_units(pointer->pos.y, &state)); + + if (g->drag_status == drag_BROWSER_TEXT_SELECTION) + { + struct browser_action msg; + msg.type = act_ALTER_SELECTION; + msg.data.mouse.x = x; + msg.data.mouse.y = y; + browser_window_action(g->data.browser.bw, &msg); + } + + if (g->type == GUI_BROWSER_WINDOW) + { + if (g->data.browser.bw->current_content != NULL) + { + struct browser_action msg; + msg.type = act_MOUSE_AT; + msg.data.mouse.x = x; + msg.data.mouse.y = y; + browser_window_action(g->data.browser.bw, &msg); + } + } +} + +void ro_gui_window_click(gui_window* g, wimp_pointer* pointer) +{ + struct browser_action msg; + int x,y; + wimp_window_state state; + state.w = pointer->w; + wimp_get_window_state(&state); + + if (g->type == GUI_BROWSER_WINDOW) + { + x = browser_x_units(window_x_units(pointer->pos.x, &state)); + y = browser_y_units(window_y_units(pointer->pos.y, &state)); + + if (g->data.browser.bw->current_content != NULL) + { + if (g->data.browser.bw->current_content->type == CONTENT_HTML) + { + if (pointer->buttons == wimp_CLICK_SELECT && g->data.browser.bw->current_content->data.html.text_selection.selected == 1) + msg.type = act_CLEAR_SELECTION; + else if (pointer->buttons == wimp_CLICK_ADJUST && g->data.browser.bw->current_content->data.html.text_selection.selected == 1) + msg.type = act_ALTER_SELECTION; + else if (pointer->buttons == wimp_DRAG_SELECT || + pointer->buttons == wimp_DRAG_ADJUST) + { + wimp_drag drag; + struct ro_gui_drag_info drag_info; + + msg.type = act_START_NEW_SELECTION; + if (pointer->buttons == wimp_DRAG_ADJUST && g->data.browser.bw->current_content->data.html.text_selection.selected == 1) + msg.type = act_ALTER_SELECTION; + + drag.type = wimp_DRAG_USER_POINT; + drag.initial.x0 = pointer->pos.x; + drag.initial.y0 = pointer->pos.y; + drag.initial.x1 = pointer->pos.x; + drag.initial.y1 = pointer->pos.y; + drag.bbox.x0 = state.visible.x0; + drag.bbox.y0 = state.visible.y0; + drag.bbox.x1 = state.visible.x1; + drag.bbox.y1 = state.visible.y1; + drag_info.type = draginfo_BROWSER_TEXT_SELECTION; + drag_info.data.selection.gui = g; + ro_gui_drag_box(&drag, &drag_info); + g->drag_status = drag_BROWSER_TEXT_SELECTION; + } + msg.data.mouse.x = x; + msg.data.mouse.y = y; + if (msg.type != act_UNKNOWN) + browser_window_action(g->data.browser.bw, &msg); + + if (pointer->buttons == wimp_CLICK_ADJUST && g->data.browser.bw->current_content->data.html.text_selection.selected == 1) + { + current_drag.data.selection.gui->data.browser.bw->current_content->data.html.text_selection.altering = alter_UNKNOWN; + } + + if (pointer->buttons == wimp_CLICK_SELECT + || pointer->buttons == wimp_CLICK_ADJUST) + { + if (pointer->buttons == wimp_CLICK_SELECT) + msg.type = act_FOLLOW_LINK; + else + msg.type = act_FOLLOW_LINK_NEW_WINDOW; + msg.data.mouse.x = x; + msg.data.mouse.y = y; + browser_window_action(g->data.browser.bw, &msg); + } + } + } + } +} + +struct ro_gui_poll_block +{ + wimp_event_no event; + wimp_block* block; + struct ro_gui_poll_block* next; +}; + +struct ro_gui_poll_block* ro_gui_poll_queued_blocks = NULL; + +void ro_gui_poll_queue(wimp_event_no event, wimp_block* block) +{ + struct ro_gui_poll_block* q = xcalloc(1, sizeof(struct ro_gui_poll_block)); + + q->event = event; + q->block = xcalloc(1, sizeof(block)); + memcpy(q->block, block, sizeof(block)); + q->next = NULL; + + if (ro_gui_poll_queued_blocks == NULL) + { + ro_gui_poll_queued_blocks = q; + return; + } + else + { + struct ro_gui_poll_block* current = ro_gui_poll_queued_blocks; + while (current->next != NULL) + current = current->next; + current->next = q; + } + return; +} + +void gui_multitask(void) +{ + wimp_event_no event; + wimp_block block; + gui_window* g; + + event = wimp_poll(wimp_QUEUE_KEY | + wimp_MASK_LOSE | wimp_MASK_GAIN | wimp_MASK_POLLWORD, &block, 0); + + switch (event) + { + case wimp_NULL_REASON_CODE: + if (over_window != NULL) + { + wimp_pointer pointer; + wimp_get_pointer_info(&pointer); + ro_gui_window_mouse_at(&pointer); + } + break; + + case wimp_REDRAW_WINDOW_REQUEST : + g = ro_lookup_gui_from_w(block.redraw.w); + if (g != NULL) + ro_gui_window_redraw(g, &(block.redraw)); + break; + + case wimp_OPEN_WINDOW_REQUEST : + g = ro_lookup_gui_from_w(block.open.w); + if (g != NULL) + ro_gui_window_open(g, &(block.open)); + break; + + case wimp_CLOSE_WINDOW_REQUEST : + ro_gui_poll_queue(event, &block); + break; + + case wimp_MOUSE_CLICK : + if (block.pointer.w == wimp_ICON_BAR) + ro_gui_icon_bar_click(&(block.pointer)); + else + { + g = ro_lookup_gui_from_w(block.pointer.w); + if (g != NULL) + { + if (g->redraw_safety == SAFE) + ro_gui_window_click(g, &(block.pointer)); + else + ro_gui_poll_queue(event, &block); + } + else + ro_gui_poll_queue(event, &block); + } + break; + + case wimp_POINTER_LEAVING_WINDOW : + over_window = NULL; + break; + case wimp_POINTER_ENTERING_WINDOW : + over_window = ro_lookup_gui_from_w(block.leaving.w); + break; + case wimp_USER_DRAG_BOX : + ro_gui_drag_end(&(block.dragged)); + break; + case wimp_MENU_SELECTION : + case wimp_USER_MESSAGE : + case wimp_USER_MESSAGE_RECORDED : + case wimp_USER_MESSAGE_ACKNOWLEDGE: + if (block.message.action == message_QUIT) + netsurf_quit = 1; + else + ro_gui_poll_queue(event, &block); + break; + default: + break; + } + +} + +void ro_gui_keypress(wimp_key* key) +{ + gui_window* g; + + if (key == NULL) + return; + + g = ro_lookup_gui_toolbar_from_w(key->w); + if (g != NULL) + { + if (key->c == wimp_KEY_RETURN) + { + if (g->data.browser.bw->url != NULL) + { + xfree(g->data.browser.bw->url); + g->data.browser.bw->url = NULL; + } + browser_window_open_location(g->data.browser.bw, g->url); + return; + } + } + wimp_process_key(key->c); + return; +} + +void gui_poll(void) +{ + wimp_event_no event; + wimp_block block; + gui_window* g; + int finished = 0; + + do + { + if (ro_gui_poll_queued_blocks == NULL) + { + event = wimp_poll(0, &block, 0); + finished = 1; + } + else + { + struct ro_gui_poll_block* next; + event = ro_gui_poll_queued_blocks->event; + memcpy(&block, ro_gui_poll_queued_blocks->block, sizeof(block)); + next = ro_gui_poll_queued_blocks->next; + xfree(ro_gui_poll_queued_blocks->block); + xfree(ro_gui_poll_queued_blocks); + ro_gui_poll_queued_blocks = next; + finished = 0; + } + switch (event) + { + case wimp_NULL_REASON_CODE : + if (over_window != NULL + || current_drag.type == draginfo_BROWSER_TEXT_SELECTION) + { + wimp_pointer pointer; + wimp_get_pointer_info(&pointer); + ro_gui_window_mouse_at(&pointer); + } + break; + + case wimp_REDRAW_WINDOW_REQUEST : + g = ro_lookup_gui_from_w(block.redraw.w); + if (g != NULL) + ro_gui_window_redraw(g, &(block.redraw)); + break; + + case wimp_OPEN_WINDOW_REQUEST : + g = ro_lookup_gui_from_w(block.open.w); + if (g != NULL) + ro_gui_window_open(g, &(block.open)); + break; + + case wimp_CLOSE_WINDOW_REQUEST : + g = ro_lookup_gui_from_w(block.close.w); + if (g != NULL) + gui_window_hide(g); + break; + + case wimp_POINTER_LEAVING_WINDOW : + g = ro_lookup_gui_from_w(block.leaving.w); + if (g == over_window) + over_window = NULL; + break; + + case wimp_POINTER_ENTERING_WINDOW : + g = ro_lookup_gui_from_w(block.entering.w); + if (g != NULL) + over_window = g; + break; + + case wimp_MOUSE_CLICK : + if (block.pointer.w == wimp_ICON_BAR) + ro_gui_icon_bar_click(&(block.pointer)); + else + { + g = ro_lookup_gui_from_w(block.pointer.w); + if (g != NULL) + ro_gui_window_click(g, &(block.pointer)); + } + break; + + case wimp_USER_DRAG_BOX : + ro_gui_drag_end(&(block.dragged)); + break; + + case wimp_KEY_PRESSED : + ro_gui_keypress(&(block.key)); + break; + + case wimp_MENU_SELECTION : + break; + + case wimp_LOSE_CARET : + break; + case wimp_GAIN_CARET : + break; + + case wimp_USER_MESSAGE : + case wimp_USER_MESSAGE_RECORDED : + case wimp_USER_MESSAGE_ACKNOWLEDGE: + if (block.message.action == message_QUIT) + netsurf_quit = 1; + break; + } + } while (finished == 0); + + return; +} + +int gui_file_to_filename(char* location, char* actual_filename, int size) +{ + char* current; + int count = 0; + + if (strspn(location, "file:/") != strlen("file:/")) + return -1; + + current = location + strlen("file:/"); + while (*current != '\0' && count < size - 1) + { + if (strspn(current, "..") == 2) + { + if (actual_filename != NULL) + actual_filename[count] = '^'; + count++; + current += 2; + } + if (*current == '/') + { + if (actual_filename != NULL) + actual_filename[count] = '.'; + count++; + current += 1; + } + else if (*current == '.') + { + if (actual_filename != NULL) + actual_filename[count] = '/'; + count++; + current += 1; + } + else + { + if (actual_filename != NULL) + actual_filename[count] = *current; + count++; + current += 1; + } + } + + if (actual_filename != NULL) + actual_filename[count] = '\0'; + + return count + 1; +} + diff --git a/riscos/gui.h b/riscos/gui.h new file mode 100644 index 000000000..c7644623d --- /dev/null +++ b/riscos/gui.h @@ -0,0 +1,47 @@ +/** + * $Id: gui.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $ + */ + +#ifndef _NETSURF_RISCOS_GUI_H_ +#define _NETSURF_RISCOS_GUI_H_ + +#include "oslib/wimp.h" + +struct ro_gui_window; +typedef struct ro_gui_window gui_window; + + int ro_x_units (int browser_units); + int ro_y_units (int browser_units); + int browser_x_units (int ro_units) ; + int browser_y_units (int ro_units) ; + +struct ro_gui_window +{ + gui_window_type type; + + union { + struct { + wimp_w window; + wimp_w toolbar; + struct browser_window* bw; + } browser; + } data; + + char status[256]; + char title[256]; + char url[256]; + gui_window* next; + + gui_safety redraw_safety; + enum { drag_NONE, drag_UNKNOWN, drag_BROWSER_TEXT_SELECTION } drag_status; +}; + +#include "netsurf/desktop/browser.h" + +void ro_gui_window_click(gui_window* g, wimp_pointer* mouse); +//void ro_gui_window_mouse_at(gui_window* g, wimp_pointer* mouse); +void ro_gui_window_open(gui_window* g, wimp_open* open); +void ro_gui_window_redraw(gui_window* g, wimp_draw* redraw); +//void ro_gui_window_keypress(gui_window* g, wimp_key* key); + +#endif diff --git a/utils/utils.c b/utils/utils.c index ffdf029ae..923c16e26 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -1,5 +1,5 @@ /** - * $Id: utils.c,v 1.4 2002/06/21 18:16:24 bursa Exp $ + * $Id: utils.c,v 1.5 2002/09/11 14:24:02 monkeyson Exp $ */ #include @@ -46,6 +46,14 @@ void * xrealloc(void * p, const size_t size) return p; } +void xfree(void* p) +{ + if (p == 0) + fprintf(stderr, "Attempt to free NULL pointer\n"); + else + free(p); +} + char * xstrdup(const char * const s) { char * c = malloc(strlen(s) + 1); -- cgit v1.2.3