From b010a257712b3d104035cbfc15aba8f517ffacb5 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Fri, 4 Jun 2010 09:35:08 +0000 Subject: + Refactor input handling from browser window code into content handlers. + Disentangle all box tree manipulation from browser window code and put it where it belongs. + Move other content specific and other irrelevant code from browser window handling to appropriate places. + Put mouse state enum in new mouse header, since it's not just used by browser window code, and it is used by treeview windows on the treeview branch. svn path=/trunk/netsurf/; revision=10561 --- Makefile.sources | 4 +- amiga/gui.c | 13 +- beos/beos_gui.cpp | 4 +- beos/beos_window.cpp | 1 + content/content.c | 108 +++- content/content.h | 5 + desktop/browser.c | 1531 ++------------------------------------------- desktop/browser.h | 58 +- desktop/gui.h | 4 +- desktop/history_core.c | 1 + desktop/mouse.h | 66 ++ desktop/scroll.c | 1 + desktop/selection.c | 1 + desktop/textarea.c | 1 + desktop/textinput.c | 13 +- framebuffer/gui.c | 1 + gtk/gtk_gui.c | 4 +- gtk/gtk_window.c | 1 + render/box.c | 235 ++++++- render/box.h | 2 + render/form.c | 231 ++++++- render/form.h | 7 + render/html.c | 45 ++ render/html.h | 23 +- render/html_interaction.c | 882 ++++++++++++++++++++++++++ render/textplain.c | 88 +++ render/textplain.h | 5 + riscos/menus.c | 4 +- riscos/window.c | 1 + windows/gui.c | 3 +- 30 files changed, 1770 insertions(+), 1573 deletions(-) create mode 100644 desktop/mouse.h create mode 100644 render/html_interaction.c diff --git a/Makefile.sources b/Makefile.sources index 851d89575..ed3c6751f 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -9,8 +9,8 @@ S_CONTENT := content.c fetch.c hlcache.c llcache.c urldb.c \ fetchers/fetch_curl.c fetchers/fetch_data.c S_CSS := css.c dump.c internal.c select.c utils.c S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \ - font.c form.c html.c html_redraw.c hubbub_binding.c imagemap.c \ - layout.c list.c table.c textplain.c + font.c form.c html.c html_interaction.c html_redraw.c \ + hubbub_binding.c imagemap.c layout.c list.c table.c textplain.c S_UTILS := base64.c filename.c hashtable.c http.c locale.c \ messages.c talloc.c url.c utf8.c utils.c useragent.c S_DESKTOP := knockout.c options.c plot_style.c print.c search.c \ diff --git a/amiga/gui.c b/amiga/gui.c index cf47ebc5e..bd50b8a12 100755 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -20,6 +20,7 @@ #include "content/urldb.h" #include "css/utils.h" #include "desktop/history_core.h" +#include "desktop/mouse.h" #include "desktop/netsurf.h" #include "desktop/options.h" #include "desktop/save_complete.h" @@ -3758,14 +3759,14 @@ void ami_scroller_hook(struct Hook *hook,Object *object,struct IntuiMessage *msg uint32 ami_popup_hook(struct Hook *hook,Object *item,APTR reserved) { - int32 itemid = 0; + int32 itemid = 0; struct gui_window *gwin = hook->h_Data; - if(GetAttr(PMIA_ID, item, &itemid)) - { - browser_window_form_select(gwin->shared->bw,gwin->shared->control,itemid); - } + if(GetAttr(PMIA_ID, item, &itemid)) + { + form_select_process_selection(gwin->shared->bw->current_content,gwin->shared->control,itemid); + } - return itemid; + return itemid; } diff --git a/beos/beos_gui.cpp b/beos/beos_gui.cpp index 471f4e9ea..83af4b682 100644 --- a/beos/beos_gui.cpp +++ b/beos/beos_gui.cpp @@ -805,8 +805,8 @@ void gui_download_window_done(struct gui_download_window *dw) static void nsbeos_select_menu_clicked(BCheckMenuItem *checkmenuitem, gpointer user_data) { - browser_window_form_select(select_menu_bw, select_menu_control, - (intptr_t)user_data); + form_select_process_selection(select_menu_bw->current_content, + select_menu_control, (intptr_t)user_data); } #endif diff --git a/beos/beos_window.cpp b/beos/beos_window.cpp index 5a9ddf2bf..23c63635f 100644 --- a/beos/beos_window.cpp +++ b/beos/beos_window.cpp @@ -23,6 +23,7 @@ extern "C" { #include "content/urldb.h" #include "desktop/browser.h" +#include "desktop/mouse.h" #include "desktop/options.h" #include "desktop/selection.h" #include "desktop/textinput.h" diff --git a/content/content.c b/content/content.c index f6ccb38ec..3f81de3a9 100644 --- a/content/content.c +++ b/content/content.c @@ -36,6 +36,7 @@ #include "content/hlcache.h" #include "css/css.h" #include "image/bitmap.h" +#include "desktop/browser.h" #include "desktop/options.h" #include "render/directory.h" #include "render/html.h" @@ -253,6 +254,10 @@ struct handler_entry { void (*reformat)(struct content *c, int width, int height); void (*destroy)(struct content *c); void (*stop)(struct content *c); + void (*mouse_track)(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); + void (*mouse_action)(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); bool (*redraw)(struct content *c, int x, int y, int width, int height, int clip_x0, int clip_y0, int clip_x1, int clip_y1, @@ -275,88 +280,92 @@ struct handler_entry { * Must be ordered as enum ::content_type. */ static const struct handler_entry handler_map[] = { {html_create, html_process_data, html_convert, - html_reformat, html_destroy, html_stop, html_redraw, 0, - html_open, html_close, html_clone, - true}, + html_reformat, html_destroy, html_stop, html_mouse_track, + html_mouse_action, html_redraw, 0, html_open, html_close, + html_clone, true}, {textplain_create, textplain_process_data, textplain_convert, - textplain_reformat, textplain_destroy, 0, textplain_redraw, 0, - 0, 0, textplain_clone, true}, + textplain_reformat, textplain_destroy, 0, textplain_mouse_track, + textplain_mouse_action, textplain_redraw, 0, 0, 0, + textplain_clone, true}, {nscss_create, nscss_process_data, nscss_convert, 0, nscss_destroy, - 0, 0, 0, 0, 0, nscss_clone, false}, + 0, 0, 0, 0, 0, 0, 0, nscss_clone, false}, #ifdef WITH_JPEG - {0, 0, nsjpeg_convert, 0, nsjpeg_destroy, 0, + {0, 0, nsjpeg_convert, 0, nsjpeg_destroy, 0, 0, 0, nsjpeg_redraw, nsjpeg_redraw_tiled, 0, 0, nsjpeg_clone, false}, #endif #ifdef WITH_GIF - {nsgif_create, 0, nsgif_convert, 0, nsgif_destroy, 0, + {nsgif_create, 0, nsgif_convert, 0, nsgif_destroy, 0, 0, 0, nsgif_redraw, nsgif_redraw_tiled, 0, 0, nsgif_clone, false}, #endif #ifdef WITH_BMP - {nsbmp_create, 0, nsbmp_convert, 0, nsbmp_destroy, 0, + {nsbmp_create, 0, nsbmp_convert, 0, nsbmp_destroy, 0, 0, 0, nsbmp_redraw, nsbmp_redraw_tiled, 0, 0, nsbmp_clone, false}, - {nsico_create, 0, nsico_convert, 0, nsico_destroy, 0, + {nsico_create, 0, nsico_convert, 0, nsico_destroy, 0, 0, 0, nsico_redraw, nsico_redraw_tiled, 0, 0, nsico_clone, false}, #endif #ifdef WITH_PNG {nspng_create, nspng_process_data, nspng_convert, - 0, nspng_destroy, 0, nspng_redraw, nspng_redraw_tiled, + 0, nspng_destroy, 0, 0, 0, nspng_redraw, nspng_redraw_tiled, 0, 0, nspng_clone, false}, #else #ifdef WITH_MNG {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled, + 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, 0, 0, nsmng_clone, false}, #endif #endif #ifdef WITH_MNG {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled, + 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, 0, 0, nsmng_clone, false}, {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled, + 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, 0, 0, nsmng_clone, false}, #endif #ifdef WITH_SPRITE {0, 0, sprite_convert, - 0, sprite_destroy, 0, sprite_redraw, 0, + 0, sprite_destroy, 0, 0, 0, sprite_redraw, 0, 0, 0, sprite_clone, false}, #endif #ifdef WITH_NSSPRITE {0, 0, nssprite_convert, - 0, nssprite_destroy, 0, nssprite_redraw, 0, + 0, nssprite_destroy, 0, 0, 0, nssprite_redraw, 0, 0, 0, nssprite_clone, false}, #endif #ifdef WITH_DRAW {0, 0, draw_convert, - 0, draw_destroy, 0, draw_redraw, 0, 0, 0, draw_clone, false}, + 0, draw_destroy, 0, 0, 0, draw_redraw, 0, 0, 0, draw_clone, + false}, #endif #ifdef WITH_PLUGIN {plugin_create, 0, plugin_convert, - plugin_reformat, plugin_destroy, 0, plugin_redraw, 0, + plugin_reformat, plugin_destroy, 0, plugin_redraw, 0, 0, 0, plugin_open, plugin_close, plugin_clone, true}, #endif {directory_create, 0, directory_convert, - 0, directory_destroy, 0, 0, 0, 0, 0, directory_clone, true}, + 0, directory_destroy, 0, 0, 0, 0, 0, 0, 0, directory_clone, + true}, #ifdef WITH_THEME_INSTALL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}, #endif #ifdef WITH_ARTWORKS {0, 0, artworks_convert, - 0, artworks_destroy, 0, artworks_redraw, 0, + 0, artworks_destroy, 0, 0, 0, artworks_redraw, 0, 0, 0, artworks_clone, false}, #endif #ifdef WITH_NS_SVG {svg_create, 0, svg_convert, - svg_reformat, svg_destroy, 0, svg_redraw, 0, + svg_reformat, svg_destroy, 0, 0, 0, svg_redraw, 0, 0, 0, svg_clone, true}, #endif #ifdef WITH_RSVG {rsvg_create, rsvg_process_data, rsvg_convert, - 0, rsvg_destroy, 0, rsvg_redraw, 0, 0, 0, rsvg_clone, false}, + 0, rsvg_destroy, 0, 0, 0, rsvg_redraw, 0, 0, 0, rsvg_clone, + false}, #endif - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false} + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false} }; #define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) @@ -752,6 +761,57 @@ void content_destroy(struct content *c) talloc_free(c); } + +/** + * Handle mouse movements in a content window. + * + * \param h Content handle + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ + +void content_mouse_track(hlcache_handle *h, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + struct content *c = hlcache_handle_get_content(h); + assert(c != NULL); + + if (handler_map[c->type].mouse_track) + handler_map[c->type].mouse_track(c, bw, mouse, x, y); + return; +} + + +/** + * Handle mouse clicks and movements in a content window. + * + * \param h Content handle + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + * + * This function handles both hovering and clicking. It is important that the + * code path is identical (except that hovering doesn't carry out the action), + * so that the status bar reflects exactly what will happen. Having separate + * code paths opens the possibility that an attacker will make the status bar + * show some harmless action where clicking will be harmful. + */ + +void content_mouse_action(hlcache_handle *h, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + struct content *c = hlcache_handle_get_content(h); + assert(c != NULL); + + if (handler_map[c->type].mouse_action) + handler_map[c->type].mouse_action(c, bw, mouse, x, y); + return; +} + + /** * Request a redraw of an area of a content * diff --git a/content/content.h b/content/content.h index 652409533..f6d293ea2 100644 --- a/content/content.h +++ b/content/content.h @@ -31,6 +31,7 @@ #include "utils/config.h" #include "utils/errors.h" #include "content/content_type.h" +#include "desktop/mouse.h" #include "desktop/plot_style.h" struct box; @@ -117,6 +118,10 @@ bool content_can_reformat(struct hlcache_handle *h); void content_reformat(struct hlcache_handle *h, int width, int height); void content_request_redraw(struct hlcache_handle *h, int x, int y, int width, int height); +void content_mouse_track(struct hlcache_handle *h, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); +void content_mouse_action(struct hlcache_handle *h, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); bool content_redraw(struct hlcache_handle *h, int x, int y, int width, int height, int clip_x0, int clip_y0, int clip_x1, int clip_y1, diff --git a/desktop/browser.c b/desktop/browser.c index 04631a4df..c1a7d4f86 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -37,10 +37,10 @@ #include "curl/curl.h" #include "utils/config.h" +#include "content/content.h" #include "content/fetch.h" #include "content/hlcache.h" #include "content/urldb.h" -#include "css/css.h" #include "desktop/401login.h" #include "desktop/browser.h" #include "desktop/download.h" @@ -48,18 +48,13 @@ #include "desktop/history_core.h" #include "desktop/gui.h" #include "desktop/options.h" -#include "desktop/scroll.h" #include "desktop/selection.h" #include "desktop/textinput.h" -#include "render/box.h" #include "render/form.h" -#include "render/font.h" -#include "render/imagemap.h" -#include "render/layout.h" +#include "render/html.h" #include "render/textplain.h" #include "utils/log.h" #include "utils/messages.h" -#include "utils/talloc.h" #include "utils/url.h" #include "utils/utils.h" #include "utils/utf8.h" @@ -73,11 +68,6 @@ bool browser_reformat_pending; /** maximum frame depth */ #define FRAME_DEPTH 8 -static void browser_window_go_post(struct browser_window *bw, - const char *url, char *post_urlenc, - struct fetch_multipart_data *post_multipart, - bool add_to_history, const char *referer, bool download, - bool verifiable, hlcache_handle *parent); static nserror browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw); static void browser_window_refresh(void *p); @@ -87,44 +77,13 @@ static void browser_window_convert_to_download(struct browser_window *bw, static void browser_window_start_throbber(struct browser_window *bw); static void browser_window_stop_throbber(struct browser_window *bw); static void browser_window_set_icon(struct browser_window *bw); -static void browser_window_set_status(struct browser_window *bw, - const char *text); -static void browser_window_set_pointer(struct gui_window *g, - gui_pointer_shape shape); static void browser_window_destroy_children(struct browser_window *bw); static void browser_window_destroy_internal(struct browser_window *bw); static void browser_window_set_scale_internal(struct browser_window *bw, float scale); -static struct browser_window *browser_window_find_target( - struct browser_window *bw, const char *target, - browser_mouse_state mouse); static void browser_window_find_target_internal(struct browser_window *bw, const char *target, int depth, struct browser_window *page, int *rdepth, struct browser_window **bw_target); -static void browser_window_mouse_action_html(struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static void browser_window_mouse_action_text(struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static void browser_window_mouse_track_html(struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static void browser_window_mouse_track_text(struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static void browser_radio_set(hlcache_handle *content, - struct form_control *radio); -static gui_pointer_shape get_pointer_shape(struct browser_window *bw, - struct box *box, bool imagemap); -static bool browser_window_nearer_text_box(struct box *box, int bx, int by, - int x, int y, int dir, struct box **nearest, int *tx, int *ty, - int *nr_xd, int *nr_yd); -static bool browser_window_nearest_text_box(struct box *box, int bx, int by, - int fx, int fy, int x, int y, int dir, struct box **nearest, - int *tx, int *ty, int *nr_xd, int *nr_yd); -static struct box *browser_window_pick_text_box(struct browser_window *bw, - int x, int y, int dir, int *dx, int *dy); -static void browser_window_page_drag_start(struct browser_window *bw, - int x, int y); -static void browser_window_box_drag_start(struct browser_window *bw, - struct box *box, int x, int y); /** * Create and open a new browser window with the given page. @@ -787,7 +746,6 @@ void browser_window_set_icon(struct browser_window *bw) void browser_window_update(struct browser_window *bw, bool scroll_to_top) { - struct box *pos; int x, y; if (bw->current_content == NULL) @@ -803,14 +761,9 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top) /** \todo don't do this if the user has scrolled */ /* if frag_id exists, then try to scroll to it */ - if (bw->frag_id && - content_get_type(bw->current_content) == CONTENT_HTML) { - struct box *layout = html_get_box_tree(bw->current_content); - - if ((pos = box_find_by_id(layout, bw->frag_id)) != 0) { - box_coords(pos, &x, &y); - gui_window_set_scroll(bw->window, x, y); - } + if (bw->frag_id && html_get_id_offset(bw->current_content, bw->frag_id, + &x, &y)) { + gui_window_set_scroll(bw->window, x, y); } gui_window_redraw_window(bw->window); @@ -1361,633 +1314,6 @@ void browser_window_find_target_internal(struct browser_window *bw, } -/** - * Handle mouse clicks in a browser window. - * - * \param bw browser window - * \param mouse state of mouse buttons and modifier keys - * \param x coordinate of mouse - * \param y coordinate of mouse - */ - -void browser_window_mouse_click(struct browser_window *bw, - browser_mouse_state mouse, int x, int y) -{ - hlcache_handle *c = bw->current_content; - - if (!c) - return; - - switch (content_get_type(c)) { - case CONTENT_HTML: - browser_window_mouse_action_html(bw, mouse, x, y); - break; - - case CONTENT_TEXTPLAIN: - browser_window_mouse_action_text(bw, mouse, x, y); - break; - - default: - if (mouse & BROWSER_MOUSE_MOD_2) { - if (mouse & BROWSER_MOUSE_DRAG_2) - gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, c, - bw->window); - else if (mouse & BROWSER_MOUSE_DRAG_1) - gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, c, - bw->window); - } - else if (mouse & (BROWSER_MOUSE_DRAG_1 | - BROWSER_MOUSE_DRAG_2)) { - browser_window_page_drag_start(bw, x, y); - browser_window_set_pointer(bw->window, GUI_POINTER_MOVE); - } - break; - } -} - - -/** - * Handle mouse clicks and movements in an HTML content window. - * - * \param bw browser window - * \param mouse state of mouse buttons and modifier keys - * \param x coordinate of mouse - * \param y coordinate of mouse - * - * This function handles both hovering and clicking. It is important that the - * code path is identical (except that hovering doesn't carry out the action), - * so that the status bar reflects exactly what will happen. Having separate - * code paths opens the possibility that an attacker will make the status bar - * show some harmless action where clicking will be harmful. - */ - -void browser_window_mouse_action_html(struct browser_window *bw, - browser_mouse_state mouse, int x, int y) -{ - enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE; - char *title = 0; - const char *url = 0; - const char *target = 0; - char status_buffer[200]; - const char *status = 0; - gui_pointer_shape pointer = GUI_POINTER_DEFAULT; - bool imagemap = false; - int box_x = 0, box_y = 0; - int gadget_box_x = 0, gadget_box_y = 0; - int text_box_x = 0; - struct box *url_box = 0; - struct box *gadget_box = 0; - struct box *text_box = 0; - hlcache_handle *c = bw->current_content; - struct box *box; - hlcache_handle *content = c; - hlcache_handle *gadget_content = c; - struct form_control *gadget = 0; - hlcache_handle *object = NULL; - struct box *next_box; - struct box *drag_candidate = NULL; - struct scroll *scroll = NULL; - plot_font_style_t fstyle; - int scroll_mouse_x = 0, scroll_mouse_y = 0; - int padding_left, padding_right, padding_top, padding_bottom; - - - if (bw->visible_select_menu != NULL) { - box = bw->visible_select_menu->box; - box_coords(box, &box_x, &box_y); - - box_x -= box->border[LEFT].width; - box_y += box->height + box->border[BOTTOM].width + - box->padding[BOTTOM] + box->padding[TOP]; - status = form_select_mouse_action(bw->visible_select_menu, - mouse, x - box_x, y - box_y); - if (status != NULL) - browser_window_set_status(bw, status); - else { - int width, height; - form_select_get_dimensions(bw->visible_select_menu, - &width, &height); - bw->visible_select_menu = NULL; - browser_window_redraw_rect(bw, box_x, box_y, - width, height); - } - return; - } - - if (bw->scroll != NULL) { - struct browser_scroll_data *data = scroll_get_data(bw->scroll); - box = data->box; - box_coords(box, &box_x, &box_y); - if (scroll_is_horizontal(bw->scroll)) { - scroll_mouse_x = x - box_x ; - scroll_mouse_y = y - (box_y + box->padding[TOP] + - box->height + box->padding[BOTTOM] - - SCROLLBAR_WIDTH); - status = scroll_mouse_action(bw->scroll, mouse, - scroll_mouse_x, scroll_mouse_y); - } else { - scroll_mouse_x = x - (box_x + box->padding[LEFT] + - box->width + box->padding[RIGHT] - - SCROLLBAR_WIDTH); - scroll_mouse_y = y - box_y; - status = scroll_mouse_action(bw->scroll, mouse, - scroll_mouse_x, scroll_mouse_y); - } - - browser_window_set_status(bw, status); - return; - } - - bw->drag_type = DRAGGING_NONE; - - /* search the box tree for a link, imagemap, form control, or - * box with scrollbars */ - - box = html_get_box_tree(c); - - /* Consider the margins of the html page now */ - box_x = box->margin[LEFT]; - box_y = box->margin[TOP]; - - while ((next_box = box_at_point(box, x, y, &box_x, &box_y, &content)) != - NULL) { - enum css_overflow_e overflow = CSS_OVERFLOW_VISIBLE; - - box = next_box; - - if (box->style && css_computed_visibility(box->style) == - CSS_VISIBILITY_HIDDEN) - continue; - - if (box->object) - object = box->object; - - if (box->href) { - url = box->href; - target = box->target; - url_box = box; - } - - if (box->usemap) { - url = imagemap_get(content, box->usemap, - box_x, box_y, x, y, &target); - if (url) { - imagemap = true; - url_box = box; - } - } - - if (box->gadget) { - gadget_content = content; - gadget = box->gadget; - gadget_box = box; - gadget_box_x = box_x; - gadget_box_y = box_y; - if (gadget->form) - target = gadget->form->target; - } - - if (box->title) - title = box->title; - - pointer = get_pointer_shape(bw, box, false); - - if (box->style) - overflow = css_computed_overflow(box->style); - - if ((box->scroll_x != NULL || box->scroll_y != NULL) && - drag_candidate == NULL) - drag_candidate = box; - - if (box->scroll_y != NULL || box->scroll_x != NULL) { - padding_left = box_x + scroll_get_offset(box->scroll_x); - padding_right = padding_left + box->padding[LEFT] + - box->width + box->padding[RIGHT]; - padding_top = box_y + scroll_get_offset(box->scroll_y); - padding_bottom = padding_top + box->padding[TOP] + - box->height + box->padding[BOTTOM]; - - if (x > padding_left && x < padding_right && - y > padding_top && y < padding_bottom) { - /* mouse inside padding box */ - - if (box->scroll_y != NULL && x > padding_right - - SCROLLBAR_WIDTH) { - /* mouse above vertical box scroll */ - - scroll = box->scroll_y; - scroll_mouse_x = x - (padding_right - - SCROLLBAR_WIDTH); - scroll_mouse_y = y - padding_top; - break; - - } else if (box->scroll_x != NULL && - y > padding_bottom - - SCROLLBAR_WIDTH) { - /* mouse above horizontal box scroll */ - - scroll = box->scroll_x; - scroll_mouse_x = x - padding_left; - scroll_mouse_y = y - (padding_bottom - - SCROLLBAR_WIDTH); - break; - } - } - } - - if (box->text && !box->object) { - text_box = box; - text_box_x = box_x; - } - } - - /* use of box_x, box_y, or content below this point is probably a - * mistake; they will refer to the last box returned by box_at_point */ - - if (scroll) { - status = scroll_mouse_action(scroll, mouse, - scroll_mouse_x, scroll_mouse_y); - pointer = GUI_POINTER_DEFAULT; - } else if (gadget) { - switch (gadget->type) { - case GADGET_SELECT: - status = messages_get("FormSelect"); - pointer = GUI_POINTER_MENU; - if (mouse & BROWSER_MOUSE_CLICK_1 && - option_core_select_menu) { - bw->visible_select_menu = gadget; - form_open_select_menu(bw, gadget, - browser_select_menu_callback, - bw); - pointer = GUI_POINTER_DEFAULT; - } else if (mouse & BROWSER_MOUSE_CLICK_1) - gui_create_form_select_menu(bw, gadget); - break; - case GADGET_CHECKBOX: - status = messages_get("FormCheckbox"); - if (mouse & BROWSER_MOUSE_CLICK_1) { - gadget->selected = !gadget->selected; - browser_redraw_box(gadget_content, gadget_box); - } - break; - case GADGET_RADIO: - status = messages_get("FormRadio"); - if (mouse & BROWSER_MOUSE_CLICK_1) - browser_radio_set(gadget_content, gadget); - break; - case GADGET_IMAGE: - if (mouse & BROWSER_MOUSE_CLICK_1) { - gadget->data.image.mx = x - gadget_box_x; - gadget->data.image.my = y - gadget_box_y; - } - /* drop through */ - case GADGET_SUBMIT: - if (gadget->form) { - snprintf(status_buffer, sizeof status_buffer, - messages_get("FormSubmit"), - gadget->form->action); - status = status_buffer; - pointer = get_pointer_shape(bw, gadget_box, - false); - if (mouse & (BROWSER_MOUSE_CLICK_1 | - BROWSER_MOUSE_CLICK_2)) - action = ACTION_SUBMIT; - } else { - status = messages_get("FormBadSubmit"); - } - break; - case GADGET_TEXTAREA: - status = messages_get("FormTextarea"); - pointer = get_pointer_shape(bw, gadget_box, false); - - if (mouse & (BROWSER_MOUSE_PRESS_1 | - BROWSER_MOUSE_PRESS_2)) { - if (text_box && selection_root(bw->sel) != - gadget_box) - selection_init(bw->sel, gadget_box); - - browser_window_textarea_click(bw, - mouse, - gadget_box, - gadget_box_x, - gadget_box_y, - x - gadget_box_x, - y - gadget_box_y); - } - - if (text_box) { - int pixel_offset; - size_t idx; - - font_plot_style_from_css(text_box->style, - &fstyle); - - nsfont.font_position_in_string(&fstyle, - text_box->text, - text_box->length, - x - gadget_box_x - text_box->x, - &idx, - &pixel_offset); - - selection_click(bw->sel, mouse, - text_box->byte_offset + idx); - - if (selection_dragging(bw->sel)) { - bw->drag_type = DRAGGING_SELECTION; - status = messages_get("Selecting"); - } else - status = content_get_status_message(c); - } - else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); - break; - case GADGET_TEXTBOX: - case GADGET_PASSWORD: - status = messages_get("FormTextbox"); - pointer = get_pointer_shape(bw, gadget_box, false); - - if ((mouse & BROWSER_MOUSE_PRESS_1) && - !(mouse & (BROWSER_MOUSE_MOD_1 | - BROWSER_MOUSE_MOD_2))) { - browser_window_input_click(bw, - gadget_box, - gadget_box_x, - gadget_box_y, - x - gadget_box_x, - y - gadget_box_y); - } - if (text_box) { - int pixel_offset; - size_t idx; - - if (mouse & (BROWSER_MOUSE_DRAG_1 | - BROWSER_MOUSE_DRAG_2)) - selection_init(bw->sel, gadget_box); - - font_plot_style_from_css(text_box->style, - &fstyle); - - nsfont.font_position_in_string(&fstyle, - text_box->text, - text_box->length, - x - gadget_box_x - text_box->x, - &idx, - &pixel_offset); - - selection_click(bw->sel, mouse, - text_box->byte_offset + idx); - - if (selection_dragging(bw->sel)) - bw->drag_type = DRAGGING_SELECTION; - } - else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); - break; - case GADGET_HIDDEN: - /* not possible: no box generated */ - break; - case GADGET_RESET: - status = messages_get("FormReset"); - break; - case GADGET_FILE: - status = messages_get("FormFile"); - break; - case GADGET_BUTTON: - /* This gadget cannot be activated */ - status = messages_get("FormButton"); - break; - } - - } else if (object && (mouse & BROWSER_MOUSE_MOD_2)) { - - if (mouse & BROWSER_MOUSE_DRAG_2) - gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, object, - bw->window); - else if (mouse & BROWSER_MOUSE_DRAG_1) - gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, object, - bw->window); - - /* \todo should have a drag-saving object msg */ - status = content_get_status_message(c); - - } else if (url) { - if (title) { - snprintf(status_buffer, sizeof status_buffer, "%s: %s", - url, title); - status = status_buffer; - } else - status = url; - - pointer = get_pointer_shape(bw, url_box, imagemap); - - if (mouse & BROWSER_MOUSE_CLICK_1 && - mouse & BROWSER_MOUSE_MOD_1) { - /* force download of link */ - browser_window_go_post(bw, url, 0, 0, false, - content_get_url(c), true, true, 0); - } else if (mouse & BROWSER_MOUSE_CLICK_2 && - mouse & BROWSER_MOUSE_MOD_1) { - gui_window_save_link(bw->window, url, title); - } else if (mouse & (BROWSER_MOUSE_CLICK_1 | - BROWSER_MOUSE_CLICK_2)) - action = ACTION_GO; - - } else { - bool done = false; - - /* frame resizing */ - if (bw->parent) { - struct browser_window *parent; - for (parent = bw->parent; parent->parent; - parent = parent->parent); - browser_window_resize_frames(parent, mouse, - x + bw->x0, y + bw->y0, - &pointer, &status, &done); - } - - /* if clicking in the main page, remove the selection from any - * text areas */ - if (!done) { - struct box *layout = html_get_box_tree(c); - - if (text_box && - (mouse & (BROWSER_MOUSE_CLICK_1 | - BROWSER_MOUSE_CLICK_2)) && - selection_root(bw->sel) != layout) - selection_init(bw->sel, layout); - - if (text_box) { - int pixel_offset; - size_t idx; - - font_plot_style_from_css(text_box->style, - &fstyle); - - nsfont.font_position_in_string(&fstyle, - text_box->text, - text_box->length, - x - text_box_x, - &idx, - &pixel_offset); - - if (selection_click(bw->sel, mouse, - text_box->byte_offset + idx)) { - /* key presses must be directed at the - * main browser window, paste text - * operations ignored */ - - if (selection_dragging(bw->sel)) { - bw->drag_type = - DRAGGING_SELECTION; - status = - messages_get("Selecting"); - } else - status = content_get_status_message(c); - - done = true; - } - } - else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); - } - - if (!done) { - if (title) - status = title; - else if (bw->loading_content) - status = content_get_status_message( - bw->loading_content); - else - status = content_get_status_message(c); - - if (mouse & BROWSER_MOUSE_DRAG_1) { - if (mouse & BROWSER_MOUSE_MOD_2) { - gui_drag_save_object(GUI_SAVE_COMPLETE, - c, bw->window); - } else { - if (drag_candidate == NULL) - browser_window_page_drag_start( - bw, x, y); - else { - browser_window_box_drag_start( - bw, - drag_candidate, - x, y); - } - pointer = GUI_POINTER_MOVE; - } - } - else if (mouse & BROWSER_MOUSE_DRAG_2) { - if (mouse & BROWSER_MOUSE_MOD_2) { - gui_drag_save_object(GUI_SAVE_SOURCE, - c, bw->window); - } else { - if (drag_candidate == NULL) - browser_window_page_drag_start( - bw, x, y); - else { - browser_window_box_drag_start( - bw, - drag_candidate, - x, y); - } - pointer = GUI_POINTER_MOVE; - } - } - } - if ((mouse & BROWSER_MOUSE_CLICK_1) && - !selection_defined(bw->sel)) { - /* ensure key presses still act on the browser window */ - browser_window_remove_caret(bw); - } - } - - - if (action == ACTION_SUBMIT || action == ACTION_GO) - bw->last_action = wallclock(); - - if (status != NULL) - browser_window_set_status(bw, status); - - browser_window_set_pointer(bw->window, pointer); - - /* deferred actions that can cause this browser_window to be destroyed - and must therefore be done after set_status/pointer - */ - switch (action) { - case ACTION_SUBMIT: - browser_form_submit(bw, - browser_window_find_target(bw, target, mouse), - gadget->form, gadget); - break; - case ACTION_GO: - browser_window_go(browser_window_find_target(bw, target, mouse), - url, content_get_url(c), true); - break; - case ACTION_NONE: - break; - } -} - - -/** - * Handle mouse clicks and movements in a TEXTPLAIN content window. - * - * \param bw browser window - * \param click type of mouse click - * \param x coordinate of mouse - * \param y coordinate of mouse - * - * This function handles both hovering and clicking. It is important that the - * code path is identical (except that hovering doesn't carry out the action), - * so that the status bar reflects exactly what will happen. Having separate - * code paths opens the possibility that an attacker will make the status bar - * show some harmless action where clicking will be harmful. - */ - -void browser_window_mouse_action_text(struct browser_window *bw, - browser_mouse_state mouse, int x, int y) -{ - hlcache_handle *c = bw->current_content; - gui_pointer_shape pointer = GUI_POINTER_DEFAULT; - const char *status = 0; - size_t idx; - int dir = 0; - - bw->drag_type = DRAGGING_NONE; - - if (!bw->sel) return; - - idx = textplain_offset_from_coords(c, x, y, dir); - if (selection_click(bw->sel, mouse, idx)) { - - if (selection_dragging(bw->sel)) { - bw->drag_type = DRAGGING_SELECTION; - status = messages_get("Selecting"); - } - else - status = content_get_status_message(c); - } - else { - if (bw->loading_content) - status = content_get_status_message( - bw->loading_content); - else - status = content_get_status_message(c); - - if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { - browser_window_page_drag_start(bw, x, y); - pointer = GUI_POINTER_MOVE; - } - } - - assert(status); - - browser_window_set_status(bw, status); - browser_window_set_pointer(bw->window, pointer); -} - - /** * Handle mouse movements in a browser window. * @@ -2029,25 +1355,13 @@ void browser_window_mouse_track(struct browser_window *bw, gui_window_set_scroll(bw->window, scrollx, scrolly); } else { assert(c != NULL); - - switch (content_get_type(c)) { - case CONTENT_HTML: - browser_window_mouse_track_html(bw, mouse, x, y); - break; - - case CONTENT_TEXTPLAIN: - browser_window_mouse_track_text(bw, mouse, x, y); - break; - - default: - break; - } + content_mouse_track(c, bw, mouse, x, y); } } /** - * Handle mouse tracking (including drags) in an HTML content window. + * Handle mouse clicks in a browser window. * * \param bw browser window * \param mouse state of mouse buttons and modifier keys @@ -2055,73 +1369,34 @@ void browser_window_mouse_track(struct browser_window *bw, * \param y coordinate of mouse */ -void browser_window_mouse_track_html(struct browser_window *bw, +void browser_window_mouse_click(struct browser_window *bw, browser_mouse_state mouse, int x, int y) { - - switch (bw->drag_type) { - case DRAGGING_SELECTION: { - struct box *box; - int dir = -1; - int dx, dy; - - if (selection_dragging_start(bw->sel)) dir = 1; - - box = browser_window_pick_text_box(bw, x, y, dir, - &dx, &dy); - if (box) { - int pixel_offset; - size_t idx; - plot_font_style_t fstyle; - - font_plot_style_from_css(box->style, &fstyle); + hlcache_handle *c = bw->current_content; - nsfont.font_position_in_string(&fstyle, - box->text, box->length, - dx, &idx, &pixel_offset); + if (!c) + return; - selection_track(bw->sel, mouse, - box->byte_offset + idx); - } - } + switch (content_get_type(c)) { + case CONTENT_HTML: + case CONTENT_TEXTPLAIN: + content_mouse_action(c, bw, mouse, x, y); break; - - default: - browser_window_mouse_action_html(bw, mouse, x, y); - break; - } -} - - -/** - * Handle mouse tracking (including drags) in a TEXTPLAIN content window. - * - * \param bw browser window - * \param mouse state of mouse buttons and modifier keys - * \param x coordinate of mouse - * \param y coordinate of mouse - */ - -void browser_window_mouse_track_text(struct browser_window *bw, - browser_mouse_state mouse, int x, int y) -{ - switch (bw->drag_type) { - - case DRAGGING_SELECTION: { - hlcache_handle *c = bw->current_content; - int dir = -1; - size_t idx; - - if (selection_dragging_start(bw->sel)) dir = 1; - - idx = textplain_offset_from_coords(c, x, y, dir); - selection_track(bw->sel, mouse, idx); + default: + if (mouse & BROWSER_MOUSE_MOD_2) { + if (mouse & BROWSER_MOUSE_DRAG_2) + gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, c, + bw->window); + else if (mouse & BROWSER_MOUSE_DRAG_1) + gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, c, + bw->window); + } + else if (mouse & (BROWSER_MOUSE_DRAG_1 | + BROWSER_MOUSE_DRAG_2)) { + browser_window_page_drag_start(bw, x, y); + browser_window_set_pointer(bw->window, GUI_POINTER_MOVE); } break; - - default: - browser_window_mouse_action_text(bw, mouse, x, y); - break; } } @@ -2135,144 +1410,55 @@ void browser_window_mouse_track_text(struct browser_window *bw, * \param y coordinate of mouse */ +// TODO: MOVE content specific stuff out + void browser_window_mouse_drag_end(struct browser_window *bw, browser_mouse_state mouse, int x, int y) { - struct box *box; - int scroll_mouse_x, scroll_mouse_y, box_x, box_y; if (bw->visible_select_menu != NULL) { - box = bw->visible_select_menu->box; - box_coords(box, &box_x, &box_y); - - box_x -= box->border[LEFT].width; - box_y += box->height + box->border[BOTTOM].width + - box->padding[BOTTOM] + box->padding[TOP]; - form_select_mouse_drag_end(bw->visible_select_menu, - mouse, x - box_x, y - box_y); + form_select_mouse_drag_end(bw->visible_select_menu, mouse, + x, y); return; } if (bw->scroll != NULL) { - struct browser_scroll_data *data = scroll_get_data(bw->scroll); - box = data->box; - box_coords(box, &box_x, &box_y); - if (scroll_is_horizontal(bw->scroll)) { - scroll_mouse_x = x - box_x; - scroll_mouse_y = y - (box_y + box->padding[TOP] + - box->height + box->padding[BOTTOM] - - SCROLLBAR_WIDTH); - scroll_mouse_drag_end(bw->scroll, mouse, - scroll_mouse_x, scroll_mouse_y); - } else { - scroll_mouse_x = x - (box_x + box->padding[LEFT] + - box->width + box->padding[RIGHT] - - SCROLLBAR_WIDTH); - scroll_mouse_y = y - box_y; - scroll_mouse_drag_end(bw->scroll, mouse, - scroll_mouse_x, scroll_mouse_y); - } + html_overflow_scroll_drag_end(bw->scroll, mouse, x, y); return; } switch (bw->drag_type) { - case DRAGGING_SELECTION: { - hlcache_handle *c = bw->current_content; - if (c) { - bool found = true; - int dir = -1; - size_t idx; - - if (selection_dragging_start(bw->sel)) dir = 1; - - if (content_get_type(c) == CONTENT_HTML) { - int pixel_offset; - struct box *box; - int dx, dy; - - box = browser_window_pick_text_box(bw, - x, y, dir, &dx, &dy); - if (box) { - plot_font_style_t fstyle; - - font_plot_style_from_css( - box->style, - &fstyle); - - nsfont.font_position_in_string( - &fstyle, - box->text, - box->length, - dx, - &idx, - &pixel_offset); - - idx += box->byte_offset; - selection_track(bw->sel, mouse, - idx); - } - else - found = false; - } - else { - assert(content_get_type(c) == - CONTENT_TEXTPLAIN); - idx = textplain_offset_from_coords(c, x, - y, dir); - } + case DRAGGING_SELECTION: { + hlcache_handle *h = bw->current_content; + if (h) { + int dir = -1; + size_t idx; + + if (selection_dragging_start(bw->sel)) + dir = 1; - if (found) + if (content_get_type(h) == CONTENT_HTML) { + idx = html_selection_drag_end(h, mouse, x, y, + dir); + if (idx != 0) selection_track(bw->sel, mouse, idx); + } else { + assert(content_get_type(h) == + CONTENT_TEXTPLAIN); + idx = textplain_offset_from_coords(h, x, y, + dir); + selection_track(bw->sel, mouse, idx); } - selection_drag_end(bw->sel); } - break; - - default: - break; + selection_drag_end(bw->sel); } + break; - bw->drag_type = DRAGGING_NONE; -} - - -/** - * Set a radio form control and clear the others in the group. - * - * \param content content containing the form, of type CONTENT_TYPE - * \param radio form control of type GADGET_RADIO - */ - -void browser_radio_set(hlcache_handle *content, - struct form_control *radio) -{ - struct form_control *control; - - assert(content); - assert(radio); - if (!radio->form) - return; - - if (radio->selected) - return; - - for (control = radio->form->controls; control; - control = control->next) { - if (control->type != GADGET_RADIO) - continue; - if (control == radio) - continue; - if (strcmp(control->name, radio->name) != 0) - continue; - - if (control->selected) { - control->selected = false; - browser_redraw_box(content, control->box); - } + default: + break; } - radio->selected = true; - browser_redraw_box(content, radio->box); + bw->drag_type = DRAGGING_NONE; } @@ -2293,577 +1479,6 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y, } -/** - * Redraw a box. - * - * \param c content containing the box, of type CONTENT_HTML - * \param box box to redraw - */ - -void browser_redraw_box(hlcache_handle *c, struct box *box) -{ - int x, y; - - box_coords(box, &x, &y); - - content_request_redraw(c, x, y, - box->padding[LEFT] + box->width + box->padding[RIGHT], - box->padding[TOP] + box->height + box->padding[BOTTOM]); -} - - -/** - * Process a selection from a form select menu. - * - * \param bw browser window with menu - * \param control form control with menu - * \param item index of item selected from the menu - */ - -void browser_window_form_select(struct browser_window *bw, - struct form_control *control, int item) -{ - struct box *inline_box; - struct form_option *o; - int count; - struct content *current_content; - - assert(bw != NULL); - assert(control != NULL); - assert(bw->current_content != NULL); - - /** \todo This must die. Browser windows have no business poking - * around inside contents */ - current_content = hlcache_handle_get_content(bw->current_content); - - inline_box = control->box->children->children; - - for (count = 0, o = control->data.select.items; - o != NULL; - count++, o = o->next) { - if (!control->data.select.multiple) - o->selected = false; - if (count == item) { - if (control->data.select.multiple) { - if (o->selected) { - o->selected = false; - control->data.select.num_selected--; - } else { - o->selected = true; - control->data.select.num_selected++; - } - } else { - o->selected = true; - } - } - if (o->selected) - control->data.select.current = o; - } - - talloc_free(inline_box->text); - inline_box->text = 0; - if (control->data.select.num_selected == 0) - inline_box->text = talloc_strdup(current_content, - messages_get("Form_None")); - else if (control->data.select.num_selected == 1) - inline_box->text = talloc_strdup(current_content, - control->data.select.current->text); - else - inline_box->text = talloc_strdup(current_content, - messages_get("Form_Many")); - if (!inline_box->text) { - warn_user("NoMemory", 0); - inline_box->length = 0; - } else - inline_box->length = strlen(inline_box->text); - inline_box->width = control->box->width; - - browser_redraw_box(bw->current_content, control->box); -} - - -gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box, - bool imagemap) -{ - gui_pointer_shape pointer; - css_computed_style *style; - enum css_cursor_e cursor; - lwc_string **cursor_uris; - bool loading; - - assert(bw); - - loading = (bw->loading_content != NULL || (bw->current_content && - content_get_status(bw->current_content) == - CONTENT_STATUS_READY)); - - if (wallclock() - bw->last_action < 100 && loading) - /* If less than 1 second since last link followed, show - * progress indicating pointer and we're loading something */ - return GUI_POINTER_PROGRESS; - - if (box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT) - style = box->children->style; - else - style = box->style; - - if (style == NULL) - return GUI_POINTER_DEFAULT; - - cursor = css_computed_cursor(style, &cursor_uris); - - switch (cursor) { - case CSS_CURSOR_AUTO: - if (box->href || (box->gadget && - (box->gadget->type == GADGET_IMAGE || - box->gadget->type == GADGET_SUBMIT)) || - imagemap) { - /* link */ - pointer = GUI_POINTER_POINT; - } else if (box->gadget && - (box->gadget->type == GADGET_TEXTBOX || - box->gadget->type == GADGET_PASSWORD || - box->gadget->type == GADGET_TEXTAREA)) { - /* text input */ - pointer = GUI_POINTER_CARET; - } else { - /* anything else */ - if (loading) { - /* loading new content */ - pointer = GUI_POINTER_PROGRESS; - } else { - pointer = GUI_POINTER_DEFAULT; - } - } - break; - case CSS_CURSOR_CROSSHAIR: - pointer = GUI_POINTER_CROSS; - break; - case CSS_CURSOR_POINTER: - pointer = GUI_POINTER_POINT; - break; - case CSS_CURSOR_MOVE: - pointer = GUI_POINTER_MOVE; - break; - case CSS_CURSOR_E_RESIZE: - pointer = GUI_POINTER_RIGHT; - break; - case CSS_CURSOR_W_RESIZE: - pointer = GUI_POINTER_LEFT; - break; - case CSS_CURSOR_N_RESIZE: - pointer = GUI_POINTER_UP; - break; - case CSS_CURSOR_S_RESIZE: - pointer = GUI_POINTER_DOWN; - break; - case CSS_CURSOR_NE_RESIZE: - pointer = GUI_POINTER_RU; - break; - case CSS_CURSOR_SW_RESIZE: - pointer = GUI_POINTER_LD; - break; - case CSS_CURSOR_SE_RESIZE: - pointer = GUI_POINTER_RD; - break; - case CSS_CURSOR_NW_RESIZE: - pointer = GUI_POINTER_LU; - break; - case CSS_CURSOR_TEXT: - pointer = GUI_POINTER_CARET; - break; - case CSS_CURSOR_WAIT: - pointer = GUI_POINTER_WAIT; - break; - case CSS_CURSOR_PROGRESS: - pointer = GUI_POINTER_PROGRESS; - break; - case CSS_CURSOR_HELP: - pointer = GUI_POINTER_HELP; - break; - default: - pointer = GUI_POINTER_DEFAULT; - break; - } - - return pointer; -} - - -/** - * Collect controls and submit a form. - */ - -void browser_form_submit(struct browser_window *bw, - struct browser_window *target, - struct form *form, struct form_control *submit_button) -{ - char *data = 0, *url = 0; - struct fetch_multipart_data *success; - - assert(form); - assert(content_get_type(bw->current_content) == CONTENT_HTML); - - if (!form_successful_controls(form, submit_button, &success)) { - warn_user("NoMemory", 0); - return; - } - - switch (form->method) { - case method_GET: - data = form_url_encode(form, success); - if (!data) { - fetch_multipart_data_destroy(success); - warn_user("NoMemory", 0); - return; - } - url = calloc(1, strlen(form->action) + - strlen(data) + 2); - if (!url) { - fetch_multipart_data_destroy(success); - free(data); - warn_user("NoMemory", 0); - return; - } - if (form->action[strlen(form->action)-1] == '?') { - sprintf(url, "%s%s", form->action, data); - } - else { - sprintf(url, "%s?%s", form->action, data); - } - browser_window_go(target, url, - content_get_url(bw->current_content), - true); - break; - - case method_POST_URLENC: - data = form_url_encode(form, success); - if (!data) { - fetch_multipart_data_destroy(success); - warn_user("NoMemory", 0); - return; - } - browser_window_go_post(target, form->action, data, 0, - true, - content_get_url(bw->current_content), - false, true, 0); - break; - - case method_POST_MULTIPART: - browser_window_go_post(target, form->action, 0, - success, true, - content_get_url(bw->current_content), - false, true, 0); - break; - - default: - assert(0); - } - - fetch_multipart_data_destroy(success); - free(data); - free(url); -} - -/** - * Callback for in-page scrolls. - */ -void browser_scroll_callback(void *client_data, - struct scroll_msg_data *scroll_data) -{ - struct browser_scroll_data *data = client_data; - struct browser_window *bw = data->bw; - struct box *box = data->box; - int x, y, box_x, box_y, diff_x, diff_y; - - - switch(scroll_data->msg) { - case SCROLL_MSG_REDRAW: - diff_x = box->padding[LEFT] + box->width + - box->padding[RIGHT] - SCROLLBAR_WIDTH; - diff_y = box->padding[TOP] + box->height + - box->padding[BOTTOM] - SCROLLBAR_WIDTH; - - box_coords(box, &box_x, &box_y); - if (scroll_is_horizontal(scroll_data->scroll)) { - x = box_x + scroll_get_offset(box->scroll_x); - y = box_y + scroll_get_offset(box->scroll_y) + - diff_y; - } else { - x = box_x + scroll_get_offset(box->scroll_x) + - diff_x; - y = box_y + scroll_get_offset(box->scroll_y); - } - browser_window_redraw_rect(bw, - x + scroll_data->x0, - y + scroll_data->y0, - scroll_data->x1 - scroll_data->x0, - scroll_data->y1 - scroll_data->y0); - break; - case SCROLL_MSG_MOVED: - browser_redraw_box(bw->current_content, box); - break; - case SCROLL_MSG_SCROLL_START: - bw->scroll = scroll_data->scroll; - gui_window_box_scroll_start(bw->window, - scroll_data->x0, scroll_data->y0, - scroll_data->x1, scroll_data->y1); - break; - case SCROLL_MSG_SCROLL_FINISHED: - bw->scroll = NULL; - - browser_window_set_pointer(bw->window, - GUI_POINTER_DEFAULT); - break; - } -} - -/** - * Callback for the core select menu. - */ -void browser_select_menu_callback(void *client_data, - int x, int y, int width, int height) -{ - struct browser_window *bw = client_data; - int menu_x, menu_y; - struct box *box; - - box = bw->visible_select_menu->box; - box_coords(box, &menu_x, &menu_y); - - menu_x -= box->border[LEFT].width; - menu_y += box->height + box->border[BOTTOM].width + - box->padding[BOTTOM] + - box->padding[TOP]; - browser_window_redraw_rect(bw, menu_x + x, menu_y + y, - width, height); -} - - -/** - * Check whether box is nearer mouse coordinates than current nearest box - * - * \param box box to test - * \param bx position of box, in global document coordinates - * \param by position of box, in global document coordinates - * \param x mouse point, in global document coordinates - * \param y mouse point, in global document coordinates - * \param dir direction in which to search (-1 = above-left, - * +1 = below-right) - * \param nearest nearest text box found, or NULL if none - * updated if box is nearer than existing nearest - * \param tx position of text_box, in global document coordinates - * updated if box is nearer than existing nearest - * \param ty position of text_box, in global document coordinates - * updated if box is nearer than existing nearest - * \param nr_xd distance to nearest text box found - * updated if box is nearer than existing nearest - * \param ny_yd distance to nearest text box found - * updated if box is nearer than existing nearest - * \return true if mouse point is inside box - */ - -bool browser_window_nearer_text_box(struct box *box, int bx, int by, - int x, int y, int dir, struct box **nearest, int *tx, int *ty, - int *nr_xd, int *nr_yd) -{ - int w = box->padding[LEFT] + box->width + box->padding[RIGHT]; - int h = box->padding[TOP] + box->height + box->padding[BOTTOM]; - int y1 = by + h; - int x1 = bx + w; - int yd = INT_MAX; - int xd = INT_MAX; - - if (x >= bx && x1 > x && y >= by && y1 > y) { - *nearest = box; - *tx = bx; - *ty = by; - return true; - } - - if (box->parent->list_marker != box) { - if (dir < 0) { - /* consider only those children (partly) above-left */ - if (by <= y && bx < x) { - yd = y <= y1 ? 0 : y - y1; - xd = x <= x1 ? 0 : x - x1; - } - } else { - /* consider only those children (partly) below-right */ - if (y1 > y && x1 > x) { - yd = y > by ? 0 : by - y; - xd = x > bx ? 0 : bx - x; - } - } - - /* give y displacement precedence over x */ - if (yd < *nr_yd || (yd == *nr_yd && xd <= *nr_xd)) { - *nr_yd = yd; - *nr_xd = xd; - *nearest = box; - *tx = bx; - *ty = by; - } - } - return false; -} - - -/** - * Pick the text box child of 'box' that is closest to and above-left - * (dir -ve) or below-right (dir +ve) of the point 'x,y' - * - * \param box parent box - * \param bx position of box, in global document coordinates - * \param by position of box, in global document coordinates - * \param fx position of float parent, in global document coordinates - * \param fy position of float parent, in global document coordinates - * \param x mouse point, in global document coordinates - * \param y mouse point, in global document coordinates - * \param dir direction in which to search (-1 = above-left, - * +1 = below-right) - * \param nearest nearest text box found, or NULL if none - * updated if a descendant of box is nearer than old nearest - * \param tx position of nearest, in global document coordinates - * updated if a descendant of box is nearer than old nearest - * \param ty position of nearest, in global document coordinates - * updated if a descendant of box is nearer than old nearest - * \param nr_xd distance to nearest text box found - * updated if a descendant of box is nearer than old nearest - * \param ny_yd distance to nearest text box found - * updated if a descendant of box is nearer than old nearest - * \return true if mouse point is inside text_box - */ - -bool browser_window_nearest_text_box(struct box *box, int bx, int by, - int fx, int fy, int x, int y, int dir, struct box **nearest, - int *tx, int *ty, int *nr_xd, int *nr_yd) -{ - struct box *child = box->children; - int c_bx, c_by; - int c_fx, c_fy; - bool in_box = false; - - if (*nearest == NULL) { - *nr_xd = INT_MAX / 2; /* displacement of 'nearest so far' */ - *nr_yd = INT_MAX / 2; - } - if (box->type == BOX_INLINE_CONTAINER) { - int bw = box->padding[LEFT] + box->width + box->padding[RIGHT]; - int bh = box->padding[TOP] + box->height + box->padding[BOTTOM]; - int b_y1 = by + bh; - int b_x1 = bx + bw; - if (x >= bx && b_x1 > x && y >= by && b_y1 > y) { - in_box = true; - } - } - - while (child) { - if (child->type == BOX_FLOAT_LEFT || - child->type == BOX_FLOAT_RIGHT) { - c_bx = fx + child->x - - scroll_get_offset(child->scroll_x); - c_by = fy + child->y - - scroll_get_offset(child->scroll_y); - } else { - c_bx = bx + child->x - - scroll_get_offset(child->scroll_x); - c_by = by + child->y - - scroll_get_offset(child->scroll_y); - } - if (child->float_children) { - c_fx = c_bx; - c_fy = c_by; - } else { - c_fx = fx; - c_fy = fy; - } - if (in_box && child->text && !child->object) { - if (browser_window_nearer_text_box(child, - c_bx, c_by, x, y, dir, nearest, - tx, ty, nr_xd, nr_yd)) - return true; - } else { - if (child->list_marker) { - if (browser_window_nearer_text_box( - child->list_marker, - c_bx + child->list_marker->x, - c_by + child->list_marker->y, - x, y, dir, nearest, - tx, ty, nr_xd, nr_yd)) - return true; - } - if (browser_window_nearest_text_box(child, c_bx, c_by, - c_fx, c_fy, x, y, dir, nearest, tx, ty, - nr_xd, nr_yd)) - return true; - } - child = child->next; - } - - return false; -} - - -/** - * Peform pick text on browser window contents to locate the box under - * the mouse pointer, or nearest in the given direction if the pointer is - * not over a text box. - * - * \param bw browser window - * \param x coordinate of mouse - * \param y coordinate of mouse - * \param dir direction to search (-1 = above-left, +1 = below-right) - * \param dx receives x ordinate of mouse relative to text box - * \param dy receives y ordinate of mouse relative to text box - */ - -struct box *browser_window_pick_text_box(struct browser_window *bw, - int x, int y, int dir, int *dx, int *dy) -{ - hlcache_handle *c = bw->current_content; - struct box *text_box = NULL; - - if (c && content_get_type(c) == CONTENT_HTML) { - struct box *box = html_get_box_tree(c); - int nr_xd, nr_yd; - int bx = box->margin[LEFT]; - int by = box->margin[TOP]; - int fx = bx; - int fy = by; - int tx, ty; - - if (!browser_window_nearest_text_box(box, bx, by, fx, fy, x, y, - dir, &text_box, &tx, &ty, &nr_xd, &nr_yd)) { - if (text_box && text_box->text && !text_box->object) { - int w = (text_box->padding[LEFT] + - text_box->width + - text_box->padding[RIGHT]); - int h = (text_box->padding[TOP] + - text_box->height + - text_box->padding[BOTTOM]); - int x1, y1; - - y1 = ty + h; - x1 = tx + w; - - /* ensure point lies within the text box */ - if (x < tx) x = tx; - if (y < ty) y = ty; - if (y > y1) y = y1; - if (x > x1) x = x1; - } - } - - /* return coordinates relative to box */ - *dx = x - tx; - *dy = y - ty; - } - - return text_box; -} - - /** * Start drag scrolling the contents of the browser window * @@ -2885,40 +1500,6 @@ void browser_window_page_drag_start(struct browser_window *bw, int x, int y) gui_window_scroll_start(bw->window); } -/** - * Start drag scrolling the contents of a box - * - * \param bw browser window - * \param box the box to be scrolled - * \param x x ordinate of initial mouse position - * \param y y ordinate - */ - -void browser_window_box_drag_start(struct browser_window *bw, - struct box *box, int x, int y) -{ - int box_x, box_y, scroll_mouse_x, scroll_mouse_y; - - box_coords(box, &box_x, &box_y); - - if (box->scroll_x != NULL) { - scroll_mouse_x = x - box_x ; - scroll_mouse_y = y - (box_y + box->padding[TOP] + - box->height + box->padding[BOTTOM] - - SCROLLBAR_WIDTH); - scroll_start_content_drag(box->scroll_x, - scroll_mouse_x, scroll_mouse_y); - } else if (box->scroll_y != NULL) { - scroll_mouse_x = x - (box_x + box->padding[LEFT] + - box->width + box->padding[RIGHT] - - SCROLLBAR_WIDTH); - scroll_mouse_y = y - box_y; - - scroll_start_content_drag(box->scroll_y, - scroll_mouse_x, scroll_mouse_y); - } -} - /** * Check availability of Back action for a given browser window diff --git a/desktop/browser.h b/desktop/browser.h index cc50521fd..292469b82 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -28,6 +28,8 @@ #include #include +#include "desktop/gui.h" +#include "desktop/mouse.h" #include "render/html.h" struct box; @@ -41,6 +43,7 @@ struct browser_window; struct url_data; struct bitmap; struct scroll_msg_data; +struct fetch_multipart_data; typedef bool (*browser_caret_callback)(struct browser_window *bw, uint32_t key, void *p); @@ -179,44 +182,6 @@ struct browser_window { int status_miss; /**< Number of times status was really updated. */ }; - -/* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS). - * 2 is secondary mouse button (e.g. Adjust on RISC OS). */ -typedef enum { - BROWSER_MOUSE_PRESS_1 = 1, /* button 1 pressed */ - BROWSER_MOUSE_PRESS_2 = 2, /* button 2 pressed */ - - /* note: click meaning is different for - * different front ends. On RISC OS, it - * is standard to act on press, so a - * click is fired at the same time as a - * mouse button is pressed. With GTK, it - * is standard to act on release, so a - * click is fired when the mouse button - * is released, if the operation wasn't - * a drag. */ - BROWSER_MOUSE_CLICK_1 = 4, /* button 1 clicked. */ - BROWSER_MOUSE_CLICK_2 = 8, /* button 2 clicked. */ - BROWSER_MOUSE_DOUBLE_CLICK = 16, /* button 1 double clicked */ - - BROWSER_MOUSE_DRAG_1 = 32, /* start of button 1 drag operation */ - BROWSER_MOUSE_DRAG_2 = 64, /* start of button 2 drag operation */ - - BROWSER_MOUSE_DRAG_ON = 128, /* a drag operation was started and - * a mouse button is still pressed */ - - BROWSER_MOUSE_HOLDING_1 = 256, /* while button 1 drag is in progress */ - BROWSER_MOUSE_HOLDING_2 = 512, /* while button 2 drag is in progress */ - - - BROWSER_MOUSE_MOD_1 = 1024, /* primary modifier key pressed - * (eg. Shift) */ - BROWSER_MOUSE_MOD_2 = 2048, /* secondary modifier key pressed - * (eg. Ctrl) */ - BROWSER_MOUSE_MOD_3 = 4096 /* secondary modifier key pressed - * (eg. Alt) */ -} browser_mouse_state; - struct browser_scroll_data { struct browser_window *bw; struct box *box; @@ -232,6 +197,11 @@ void browser_window_initialise_common(struct browser_window *bw, struct browser_window *clone); void browser_window_go(struct browser_window *bw, const char *url, const char *referrer, bool history_add); +void browser_window_go_post(struct browser_window *bw, + const char *url, char *post_urlenc, + struct fetch_multipart_data *post_multipart, + bool add_to_history, const char *referer, bool download, + bool verifiable, struct hlcache_handle *parent); void browser_window_go_unverifiable(struct browser_window *bw, const char *url, const char *referrer, bool history_add, struct hlcache_handle *parent); @@ -254,16 +224,14 @@ void browser_window_mouse_track(struct browser_window *bw, browser_mouse_state mouse, int x, int y); void browser_window_mouse_drag_end(struct browser_window *bw, browser_mouse_state mouse, int x, int y); +struct browser_window *browser_window_find_target( + struct browser_window *bw, const char *target, + browser_mouse_state mouse); bool browser_window_key_press(struct browser_window *bw, uint32_t key); bool browser_window_paste_text(struct browser_window *bw, const char *utf8, unsigned utf8_len, bool last); -void browser_window_form_select(struct browser_window *bw, - struct form_control *control, int item); void browser_redraw_box(struct hlcache_handle *c, struct box *box); -void browser_form_submit(struct browser_window *bw, - struct browser_window *target, struct form *form, - struct form_control *submit_button); void browser_scroll_callback(void *client_data, struct scroll_msg_data *scroll_data); @@ -273,6 +241,10 @@ void browser_select_menu_callback(void *client_data, void browser_window_redraw_rect(struct browser_window *bw, int x, int y, int width, int height); +void browser_window_set_status(struct browser_window *bw, const char *text); +void browser_window_set_pointer(struct gui_window *g, gui_pointer_shape shape); +void browser_window_page_drag_start(struct browser_window *bw, int x, int y); + bool browser_window_back_available(struct browser_window *bw); bool browser_window_forward_available(struct browser_window *bw); bool browser_window_reload_available(struct browser_window *bw); diff --git a/desktop/gui.h b/desktop/gui.h index 5c53cf694..ba5912ae7 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -43,6 +43,9 @@ typedef enum { struct gui_window; struct gui_download_window; +struct browser_window; +struct selection; +struct form_control; typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET, GUI_POINTER_MENU, GUI_POINTER_UP, GUI_POINTER_DOWN, @@ -56,7 +59,6 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET, #include "utils/config.h" #include "content/content.h" #include "content/hlcache.h" -#include "desktop/browser.h" #include "desktop/download.h" #include "desktop/search.h" #include "utils/errors.h" diff --git a/desktop/history_core.c b/desktop/history_core.c index fc807e928..7b7f72a38 100644 --- a/desktop/history_core.c +++ b/desktop/history_core.c @@ -30,6 +30,7 @@ #include "content/hlcache.h" #include "content/urldb.h" #include "css/css.h" +#include "desktop/browser.h" #include "desktop/gui.h" #include "desktop/history_core.h" #include "desktop/plotters.h" diff --git a/desktop/mouse.h b/desktop/mouse.h new file mode 100644 index 000000000..1d7c6cd6f --- /dev/null +++ b/desktop/mouse.h @@ -0,0 +1,66 @@ +/* + * Copyright 2003 Phil Mellor + * Copyright 2006 James Bursa + * Copyright 2010 Michael Drake + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * Browser window creation and manipulation (interface). + */ + +#ifndef _NETSURF_DESKTOP_MOUSE_H_ +#define _NETSURF_DESKTOP_MOUSE_H_ + +/* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS). + * 2 is secondary mouse button (e.g. Adjust on RISC OS). */ +typedef enum { + BROWSER_MOUSE_PRESS_1 = 1, /* button 1 pressed */ + BROWSER_MOUSE_PRESS_2 = 2, /* button 2 pressed */ + + /* note: click meaning is different for + * different front ends. On RISC OS, it + * is standard to act on press, so a + * click is fired at the same time as a + * mouse button is pressed. With GTK, it + * is standard to act on release, so a + * click is fired when the mouse button + * is released, if the operation wasn't + * a drag. */ + BROWSER_MOUSE_CLICK_1 = 4, /* button 1 clicked. */ + BROWSER_MOUSE_CLICK_2 = 8, /* button 2 clicked. */ + + BROWSER_MOUSE_DOUBLE_CLICK = 16, /* button 1 double clicked */ + + BROWSER_MOUSE_DRAG_1 = 32, /* start of button 1 drag operation */ + BROWSER_MOUSE_DRAG_2 = 64, /* start of button 2 drag operation */ + + BROWSER_MOUSE_DRAG_ON = 128, /* a drag operation was started and + * a mouse button is still pressed */ + + BROWSER_MOUSE_HOLDING_1 = 256, /* while button 1 drag is in progress */ + BROWSER_MOUSE_HOLDING_2 = 512, /* while button 2 drag is in progress */ + + + BROWSER_MOUSE_MOD_1 = 1024, /* primary modifier key pressed + * (eg. Shift) */ + BROWSER_MOUSE_MOD_2 = 2048, /* secondary modifier key pressed + * (eg. Ctrl) */ + BROWSER_MOUSE_MOD_3 = 4096 /* secondary modifier key pressed + * (eg. Alt) */ +} browser_mouse_state; + +#endif diff --git a/desktop/scroll.c b/desktop/scroll.c index 8b14e7a2a..bfa17f9c8 100644 --- a/desktop/scroll.c +++ b/desktop/scroll.c @@ -25,6 +25,7 @@ #include #include +#include "desktop/mouse.h" #include "desktop/scroll.h" #include "desktop/plotters.h" #include "desktop/plot_style.h" diff --git a/desktop/selection.c b/desktop/selection.c index 821dbb9bc..dc66fef91 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -29,6 +29,7 @@ #include "content/hlcache.h" #include "desktop/gui.h" +#include "desktop/mouse.h" #include "desktop/plotters.h" #include "desktop/save_text.h" #include "desktop/selection.h" diff --git a/desktop/textarea.c b/desktop/textarea.c index eac21699d..272fe718d 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -25,6 +25,7 @@ #include #include "css/css.h" #include "css/utils.h" +#include "desktop/mouse.h" #include "desktop/textarea.h" #include "desktop/textinput.h" #include "desktop/plotters.h" diff --git a/desktop/textinput.c b/desktop/textinput.c index 0297e952e..497467563 100644 --- a/desktop/textinput.c +++ b/desktop/textinput.c @@ -30,6 +30,7 @@ #include "desktop/browser.h" #include "desktop/gui.h" +#include "desktop/mouse.h" #include "desktop/scroll.h" #include "desktop/selection.h" #include "desktop/textinput.h" @@ -298,7 +299,7 @@ void browser_window_textarea_click(struct browser_window *bw, textarea); if (scrolled) - browser_redraw_box(bw->current_content, textarea); + html_redraw_a_box(bw->current_content, textarea); } @@ -799,7 +800,7 @@ bool browser_window_textarea_callback(struct browser_window *bw, textarea); if (scrolled || reflow) - browser_redraw_box(bw->current_content, textarea); + html_redraw_a_box(bw->current_content, textarea); return true; } @@ -862,7 +863,7 @@ void browser_window_input_click(struct browser_window* bw, input); if (dx) - browser_redraw_box(bw->current_content, input); + html_redraw_a_box(bw->current_content, input); } /** @@ -992,7 +993,7 @@ bool browser_window_input_callback(struct browser_window *bw, selection_clear(bw->sel, true); if (form) - browser_form_submit(bw, bw, form, 0); + form_submit(bw->current_content, bw, form, 0); return true; case KEY_SHIFT_TAB: @@ -1418,7 +1419,7 @@ bool browser_window_textarea_paste_text(struct browser_window *bw, browser_window_textarea_move_caret, textarea); - browser_redraw_box(bw->current_content, textarea); + html_redraw_a_box(bw->current_content, textarea); } return success; @@ -1644,7 +1645,7 @@ void input_update_display(struct browser_window *bw, struct box *input, input); if (dx || redraw) - browser_redraw_box(bw->current_content, input); + html_redraw_a_box(bw->current_content, input); } diff --git a/framebuffer/gui.c b/framebuffer/gui.c index d970fcf78..50c3da2ff 100644 --- a/framebuffer/gui.c +++ b/framebuffer/gui.c @@ -34,6 +34,7 @@ #include #include "desktop/gui.h" +#include "desktop/mouse.h" #include "desktop/plotters.h" #include "desktop/netsurf.h" #include "desktop/options.h" diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c index eec28a20a..b7cae501e 100644 --- a/gtk/gtk_gui.c +++ b/gtk/gtk_gui.c @@ -569,8 +569,8 @@ bool nsgtk_throbber_init(int framec) static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, gpointer user_data) { - browser_window_form_select(select_menu_bw, select_menu_control, - (intptr_t)user_data); + form_select_process_selection(select_menu_bw->current_content, + select_menu_control, (intptr_t)user_data); } void gui_create_form_select_menu(struct browser_window *bw, diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c index 4c8ff6178..d887f7027 100644 --- a/gtk/gtk_window.c +++ b/gtk/gtk_window.c @@ -22,6 +22,7 @@ #include "content/hlcache.h" #include "gtk/gtk_window.h" #include "desktop/browser.h" +#include "desktop/mouse.h" #include "desktop/options.h" #include "desktop/searchweb.h" #include "desktop/textinput.h" diff --git a/render/box.c b/render/box.c index e61dee8ff..439ae0353 100644 --- a/render/box.c +++ b/render/box.c @@ -2,6 +2,7 @@ * Copyright 2005-2007 James Bursa * Copyright 2003 Phil Mellor * Copyright 2005 John M Bell + * Copyright 2008 Michael Drake * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -34,11 +35,18 @@ #include "desktop/options.h" #include "render/box.h" #include "render/form.h" +#include "render/html.h" #include "utils/log.h" #include "utils/talloc.h" #include "utils/utils.h" static bool box_contains_point(struct box *box, int x, int y, bool *physically); +static bool box_nearer_text_box(struct box *box, int bx, int by, + int x, int y, int dir, struct box **nearest, int *tx, int *ty, + int *nr_xd, int *nr_yd); +static bool box_nearest_text_box(struct box *box, int bx, int by, + int fx, int fy, int x, int y, int dir, struct box **nearest, + int *tx, int *ty, int *nr_xd, int *nr_yd); #define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \ box->type == BOX_FLOAT_RIGHT) @@ -609,6 +617,229 @@ struct box *box_href_at_point(hlcache_handle *h, int x, int y) } +/** + * Check whether box is nearer mouse coordinates than current nearest box + * + * \param box box to test + * \param bx position of box, in global document coordinates + * \param by position of box, in global document coordinates + * \param x mouse point, in global document coordinates + * \param y mouse point, in global document coordinates + * \param dir direction in which to search (-1 = above-left, + * +1 = below-right) + * \param nearest nearest text box found, or NULL if none + * updated if box is nearer than existing nearest + * \param tx position of text_box, in global document coordinates + * updated if box is nearer than existing nearest + * \param ty position of text_box, in global document coordinates + * updated if box is nearer than existing nearest + * \param nr_xd distance to nearest text box found + * updated if box is nearer than existing nearest + * \param ny_yd distance to nearest text box found + * updated if box is nearer than existing nearest + * \return true if mouse point is inside box + */ + +bool box_nearer_text_box(struct box *box, int bx, int by, + int x, int y, int dir, struct box **nearest, int *tx, int *ty, + int *nr_xd, int *nr_yd) +{ + int w = box->padding[LEFT] + box->width + box->padding[RIGHT]; + int h = box->padding[TOP] + box->height + box->padding[BOTTOM]; + int y1 = by + h; + int x1 = bx + w; + int yd = INT_MAX; + int xd = INT_MAX; + + if (x >= bx && x1 > x && y >= by && y1 > y) { + *nearest = box; + *tx = bx; + *ty = by; + return true; + } + + if (box->parent->list_marker != box) { + if (dir < 0) { + /* consider only those children (partly) above-left */ + if (by <= y && bx < x) { + yd = y <= y1 ? 0 : y - y1; + xd = x <= x1 ? 0 : x - x1; + } + } else { + /* consider only those children (partly) below-right */ + if (y1 > y && x1 > x) { + yd = y > by ? 0 : by - y; + xd = x > bx ? 0 : bx - x; + } + } + + /* give y displacement precedence over x */ + if (yd < *nr_yd || (yd == *nr_yd && xd <= *nr_xd)) { + *nr_yd = yd; + *nr_xd = xd; + *nearest = box; + *tx = bx; + *ty = by; + } + } + return false; +} + + +/** + * Pick the text box child of 'box' that is closest to and above-left + * (dir -ve) or below-right (dir +ve) of the point 'x,y' + * + * \param box parent box + * \param bx position of box, in global document coordinates + * \param by position of box, in global document coordinates + * \param fx position of float parent, in global document coordinates + * \param fy position of float parent, in global document coordinates + * \param x mouse point, in global document coordinates + * \param y mouse point, in global document coordinates + * \param dir direction in which to search (-1 = above-left, + * +1 = below-right) + * \param nearest nearest text box found, or NULL if none + * updated if a descendant of box is nearer than old nearest + * \param tx position of nearest, in global document coordinates + * updated if a descendant of box is nearer than old nearest + * \param ty position of nearest, in global document coordinates + * updated if a descendant of box is nearer than old nearest + * \param nr_xd distance to nearest text box found + * updated if a descendant of box is nearer than old nearest + * \param ny_yd distance to nearest text box found + * updated if a descendant of box is nearer than old nearest + * \return true if mouse point is inside text_box + */ + +bool box_nearest_text_box(struct box *box, int bx, int by, + int fx, int fy, int x, int y, int dir, struct box **nearest, + int *tx, int *ty, int *nr_xd, int *nr_yd) +{ + struct box *child = box->children; + int c_bx, c_by; + int c_fx, c_fy; + bool in_box = false; + + if (*nearest == NULL) { + *nr_xd = INT_MAX / 2; /* displacement of 'nearest so far' */ + *nr_yd = INT_MAX / 2; + } + if (box->type == BOX_INLINE_CONTAINER) { + int bw = box->padding[LEFT] + box->width + box->padding[RIGHT]; + int bh = box->padding[TOP] + box->height + box->padding[BOTTOM]; + int b_y1 = by + bh; + int b_x1 = bx + bw; + if (x >= bx && b_x1 > x && y >= by && b_y1 > y) { + in_box = true; + } + } + + while (child) { + if (child->type == BOX_FLOAT_LEFT || + child->type == BOX_FLOAT_RIGHT) { + c_bx = fx + child->x - + scroll_get_offset(child->scroll_x); + c_by = fy + child->y - + scroll_get_offset(child->scroll_y); + } else { + c_bx = bx + child->x - + scroll_get_offset(child->scroll_x); + c_by = by + child->y - + scroll_get_offset(child->scroll_y); + } + if (child->float_children) { + c_fx = c_bx; + c_fy = c_by; + } else { + c_fx = fx; + c_fy = fy; + } + if (in_box && child->text && !child->object) { + if (box_nearer_text_box(child, + c_bx, c_by, x, y, dir, nearest, + tx, ty, nr_xd, nr_yd)) + return true; + } else { + if (child->list_marker) { + if (box_nearer_text_box( + child->list_marker, + c_bx + child->list_marker->x, + c_by + child->list_marker->y, + x, y, dir, nearest, + tx, ty, nr_xd, nr_yd)) + return true; + } + if (box_nearest_text_box(child, c_bx, c_by, + c_fx, c_fy, x, y, dir, nearest, tx, ty, + nr_xd, nr_yd)) + return true; + } + child = child->next; + } + + return false; +} + + +/** + * Peform pick text on browser window contents to locate the box under + * the mouse pointer, or nearest in the given direction if the pointer is + * not over a text box. + * + * \param h html content's high level cache handle + * \param x coordinate of mouse + * \param y coordinate of mouse + * \param dir direction to search (-1 = above-left, +1 = below-right) + * \param dx receives x ordinate of mouse relative to text box + * \param dy receives y ordinate of mouse relative to text box + */ + +struct box *box_pick_text_box(hlcache_handle *h, + int x, int y, int dir, int *dx, int *dy) +{ + struct box *text_box = NULL; + + if (h && content_get_type(h) == CONTENT_HTML) { + struct box *box = html_get_box_tree(h); + int nr_xd, nr_yd; + int bx = box->margin[LEFT]; + int by = box->margin[TOP]; + int fx = bx; + int fy = by; + int tx, ty; + + if (!box_nearest_text_box(box, bx, by, fx, fy, x, y, + dir, &text_box, &tx, &ty, &nr_xd, &nr_yd)) { + if (text_box && text_box->text && !text_box->object) { + int w = (text_box->padding[LEFT] + + text_box->width + + text_box->padding[RIGHT]); + int h = (text_box->padding[TOP] + + text_box->height + + text_box->padding[BOTTOM]); + int x1, y1; + + y1 = ty + h; + x1 = tx + w; + + /* ensure point lies within the text box */ + if (x < tx) x = tx; + if (y < ty) y = ty; + if (y > y1) y = y1; + if (x > x1) x = x1; + } + } + + /* return coordinates relative to box */ + *dx = x - tx; + *dy = y - ty; + } + + return text_box; +} + + /** * Find a box based upon its id attribute. * @@ -1095,7 +1326,7 @@ bool box_handle_scrollbars(struct browser_window *bw, struct box *box, box->descendant_y1 - box->descendant_y0, box->height, data, - browser_scroll_callback, + html_overflow_scroll_callback, &(box->scroll_y))) return false; } else @@ -1120,7 +1351,7 @@ bool box_handle_scrollbars(struct browser_window *bw, struct box *box, box->descendant_x1 - box->descendant_x0, box->width, data, - browser_scroll_callback, + html_overflow_scroll_callback, &box->scroll_x)) return false; } else diff --git a/render/box.h b/render/box.h index b6e344af1..fd1dd5e8c 100644 --- a/render/box.h +++ b/render/box.h @@ -310,6 +310,8 @@ struct box *box_at_point(struct box *box, const int x, const int y, int *box_x, int *box_y, struct hlcache_handle **content); struct box *box_object_at_point(struct hlcache_handle *h, int x, int y); struct box *box_href_at_point(struct hlcache_handle *h, int x, int y); +struct box *box_pick_text_box(struct hlcache_handle *h, + int x, int y, int dir, int *dx, int *dy); struct box *box_find_by_id(struct box *box, const char *id); bool box_visible(struct box *box); void box_dump(FILE *stream, struct box *box, unsigned int depth); diff --git a/render/form.c b/render/form.c index 9584aa244..71a42da4c 100644 --- a/render/form.c +++ b/render/form.c @@ -1,8 +1,10 @@ /* * Copyright 2004 James Bursa * Copyright 2003 Phil Mellor + * Copyright 2004 John Tytgat * Copyright 2005-9 John-Mark Bell * Copyright 2009 Paul Blokus + * Copyright 2010 Michael Drake * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -30,9 +32,12 @@ #include #include #include "content/fetch.h" +#include "content/hlcache.h" #include "css/css.h" #include "css/utils.h" +#include "desktop/browser.h" #include "desktop/gui.h" +#include "desktop/mouse.h" #include "desktop/knockout.h" #include "desktop/plot_style.h" #include "desktop/plotters.h" @@ -40,9 +45,11 @@ #include "render/box.h" #include "render/font.h" #include "render/form.h" +#include "render/html.h" #include "render/layout.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/url.h" #include "utils/utf8.h" #include "utils/utils.h" @@ -1143,7 +1150,8 @@ void form_select_menu_clicked(struct form_control *control, int x, int y) } if (option != NULL) - browser_window_form_select(menu->bw, control, i); + form_select_process_selection(menu->bw->current_content, + control, i); menu->callback(menu->client_data, 0, 0, menu->width, menu->height); } @@ -1215,12 +1223,25 @@ void form_select_mouse_drag_end(struct form_control *control, browser_mouse_state mouse, int x, int y) { int x0, y0, x1, y1; + int box_x, box_y; + struct box *box; struct form_select_menu *menu = control->data.select.menu; - + + box = control->box; + + /* Get global coords of scrollbar */ + box_coords(box, &box_x, &box_y); + box_x -= box->border[LEFT].width; + box_y += box->height + box->border[BOTTOM].width + + box->padding[BOTTOM] + box->padding[TOP]; + + /* Get drag end coords relative to scrollbar */ + x = x - box_x; + y = y - box_y; + if (menu->scroll_capture) { x -= menu->width - SCROLLBAR_WIDTH; - scroll_mouse_drag_end(menu->scroll, - mouse, x, y); + scroll_mouse_drag_end(menu->scroll, mouse, x, y); return; } @@ -1286,3 +1307,205 @@ void form_select_get_dimensions(struct form_control *control, *width = control->data.select.menu->width; *height = control->data.select.menu->height; } + + +/** + * Process a selection from a form select menu. + * + * \param bw browser window with menu + * \param control form control with menu + * \param item index of item selected from the menu + */ + +void form_select_process_selection(hlcache_handle *h, + struct form_control *control, int item) +{ + struct box *inline_box; + struct form_option *o; + int count; + struct content *current_content; + + assert(control != NULL); + assert(h != NULL); + + /** \todo Even though the form code is effectively part of the html + * content handler, poking around inside contents is not good */ + current_content = hlcache_handle_get_content(h); + + inline_box = control->box->children->children; + + for (count = 0, o = control->data.select.items; + o != NULL; + count++, o = o->next) { + if (!control->data.select.multiple) + o->selected = false; + if (count == item) { + if (control->data.select.multiple) { + if (o->selected) { + o->selected = false; + control->data.select.num_selected--; + } else { + o->selected = true; + control->data.select.num_selected++; + } + } else { + o->selected = true; + } + } + if (o->selected) + control->data.select.current = o; + } + + talloc_free(inline_box->text); + inline_box->text = 0; + if (control->data.select.num_selected == 0) + inline_box->text = talloc_strdup(current_content, + messages_get("Form_None")); + else if (control->data.select.num_selected == 1) + inline_box->text = talloc_strdup(current_content, + control->data.select.current->text); + else + inline_box->text = talloc_strdup(current_content, + messages_get("Form_Many")); + if (!inline_box->text) { + warn_user("NoMemory", 0); + inline_box->length = 0; + } else + inline_box->length = strlen(inline_box->text); + inline_box->width = control->box->width; + + html_redraw_a_box(h, control->box); +} + +/** + * Callback for the core select menu. + */ +void form_select_menu_callback(void *client_data, + int x, int y, int width, int height) +{ + struct browser_window *bw = client_data; + int menu_x, menu_y; + struct box *box; + + box = bw->visible_select_menu->box; + box_coords(box, &menu_x, &menu_y); + + menu_x -= box->border[LEFT].width; + menu_y += box->height + box->border[BOTTOM].width + + box->padding[BOTTOM] + + box->padding[TOP]; + browser_window_redraw_rect(bw, menu_x + x, menu_y + y, + width, height); +} + + +/** + * Set a radio form control and clear the others in the group. + * + * \param content content containing the form, of type CONTENT_TYPE + * \param radio form control of type GADGET_RADIO + */ + +void form_radio_set(hlcache_handle *content, + struct form_control *radio) +{ + struct form_control *control; + + assert(content); + assert(radio); + if (!radio->form) + return; + + if (radio->selected) + return; + + for (control = radio->form->controls; control; + control = control->next) { + if (control->type != GADGET_RADIO) + continue; + if (control == radio) + continue; + if (strcmp(control->name, radio->name) != 0) + continue; + + if (control->selected) { + control->selected = false; + html_redraw_a_box(content, control->box); + } + } + + radio->selected = true; + html_redraw_a_box(content, radio->box); +} + + +/** + * Collect controls and submit a form. + */ + +void form_submit(hlcache_handle *h, struct browser_window *target, + struct form *form, struct form_control *submit_button) +{ + char *data = 0, *url = 0; + struct fetch_multipart_data *success; + + assert(form); + assert(content_get_type(h) == CONTENT_HTML); + + if (!form_successful_controls(form, submit_button, &success)) { + warn_user("NoMemory", 0); + return; + } + + switch (form->method) { + case method_GET: + data = form_url_encode(form, success); + if (!data) { + fetch_multipart_data_destroy(success); + warn_user("NoMemory", 0); + return; + } + url = calloc(1, strlen(form->action) + + strlen(data) + 2); + if (!url) { + fetch_multipart_data_destroy(success); + free(data); + warn_user("NoMemory", 0); + return; + } + if (form->action[strlen(form->action)-1] == '?') { + sprintf(url, "%s%s", form->action, data); + } + else { + sprintf(url, "%s?%s", form->action, data); + } + browser_window_go(target, url, content_get_url(h), + true); + break; + + case method_POST_URLENC: + data = form_url_encode(form, success); + if (!data) { + fetch_multipart_data_destroy(success); + warn_user("NoMemory", 0); + return; + } + browser_window_go_post(target, form->action, data, 0, + true, content_get_url(h), + false, true, 0); + break; + + case method_POST_MULTIPART: + browser_window_go_post(target, form->action, 0, + success, true, content_get_url(h), + false, true, 0); + break; + + default: + assert(0); + } + + fetch_multipart_data_destroy(success); + free(data); + free(url); +} diff --git a/render/form.h b/render/form.h index d5026e039..9da24b8b9 100644 --- a/render/form.h +++ b/render/form.h @@ -157,6 +157,8 @@ bool form_open_select_menu(void *client_data, struct form_control *control, select_menu_redraw_callback redraw_callback, struct browser_window *bw); +void form_select_menu_callback(void *client_data, + int x, int y, int width, int height); void form_free_select_menu(struct form_control *control); bool form_redraw_select_menu(struct form_control *control, int x, int y, float scale, @@ -169,5 +171,10 @@ void form_select_mouse_drag_end(struct form_control *control, browser_mouse_state mouse, int x, int y); void form_select_get_dimensions(struct form_control *control, int *width, int *height); +void form_select_process_selection(hlcache_handle *h, + struct form_control *control, int item); +void form_submit(struct hlcache_handle *h, struct browser_window *target, + struct form *form, struct form_control *submit_button); +void form_radio_set(struct hlcache_handle *content, struct form_control *radio); #endif diff --git a/render/html.c b/render/html.c index c818d6e36..9367d78fb 100644 --- a/render/html.c +++ b/render/html.c @@ -1,5 +1,6 @@ /* * Copyright 2007 James Bursa + * Copyright 2010 Michael Drake * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -1740,6 +1741,25 @@ void html_reformat(struct content *c, int width, int height) } +/** + * Redraw a box. + * + * \param c content containing the box, of type CONTENT_HTML + * \param box box to redraw + */ + +void html_redraw_a_box(hlcache_handle *h, struct box *box) +{ + int x, y; + + box_coords(box, &x, &y); + + content_request_redraw(h, x, y, + box->padding[LEFT] + box->width + box->padding[RIGHT], + box->padding[TOP] + box->height + box->padding[BOTTOM]); +} + + /** * Destroy a CONTENT_HTML and free all resources it owns. */ @@ -2190,3 +2210,28 @@ hlcache_handle *html_get_favicon(hlcache_handle *h) return c->data.html.favicon; } + + +/** + * Retrieve layout coordinates of box with given id + * + * \param h HTML document to search + * \param frag_id String containing an element id + * \param x Updated to global x coord iff id found + * \param y Updated to global y coord iff id found + * \return true iff id found + */ +bool html_get_id_offset(hlcache_handle *h, char *frag_id, int *x, int *y) +{ + struct box *pos; + struct box *layout = html_get_box_tree(h); + + if (content_get_type(h) != CONTENT_HTML) + return false; + + if ((pos = box_find_by_id(layout, frag_id)) != 0) { + box_coords(pos, x, y); + return true; + } + return false; +} diff --git a/render/html.h b/render/html.h index 8977e6dd6..a5be4d939 100644 --- a/render/html.h +++ b/render/html.h @@ -28,6 +28,7 @@ #include #include "content/content_type.h" #include "css/css.h" +#include "desktop/mouse.h" #include "desktop/plot_style.h" #include "render/parser_binding.h" @@ -41,6 +42,8 @@ struct http_parameter; struct imagemap; struct object_params; struct plotters; +struct scroll; +struct scroll_msg_data; /* entries in stylesheet_content */ #define STYLESHEET_BASE 0 /* base style sheet */ @@ -202,15 +205,25 @@ void html_open(struct content *c, struct browser_window *bw, void html_close(struct content *c); void html_set_status(struct content *c, const char *extra); +void html_redraw_a_box(struct hlcache_handle *h, struct box *box); + /* in render/html_redraw.c */ bool html_redraw(struct content *c, int x, int y, int width, int height, int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale, colour background_colour); - -/* redraw a short text string, complete with highlighting - (for selection/search) and ghost caret */ +/* in render/html_interaction.c */ +void html_mouse_track(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); +void html_mouse_action(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); +void html_overflow_scroll_callback(void *client_data, + struct scroll_msg_data *scroll_data); +void html_overflow_scroll_drag_end(struct scroll *scroll, + browser_mouse_state mouse, int x, int y); +size_t html_selection_drag_end(struct hlcache_handle *h, + browser_mouse_state mouse, int x, int y, int dir); bool text_redraw(const char *utf8_text, size_t utf8_len, size_t offset, bool space, @@ -232,7 +245,9 @@ const char *html_get_base_target(struct hlcache_handle *h); struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h, unsigned int *n); struct content_html_object *html_get_objects(struct hlcache_handle *h, - unsigned int *n); + unsigned int *n); struct hlcache_handle *html_get_favicon(struct hlcache_handle *h); +bool html_get_id_offset(struct hlcache_handle *h, char *frag_id, + int *x, int *y); #endif diff --git a/render/html_interaction.c b/render/html_interaction.c new file mode 100644 index 000000000..90f8fe25f --- /dev/null +++ b/render/html_interaction.c @@ -0,0 +1,882 @@ +/* + * Copyright 2006 James Bursa + * Copyright 2006 Richard Wilson + * Copyright 2008 Michael Drake + * Copyright 2009 Paul Blokus + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * User interaction with a CONTENT_HTML (implementation). + */ + +#include +#include + +#include "content/content.h" +#include "desktop/browser.h" +#include "desktop/frames.h" +#include "desktop/mouse.h" +#include "desktop/options.h" +#include "desktop/scroll.h" +#include "desktop/selection.h" +#include "desktop/textinput.h" +#include "render/box.h" +#include "render/font.h" +#include "render/form.h" +#include "render/html.h" +#include "render/imagemap.h" +#include "utils/messages.h" +#include "utils/utils.h" + + +static gui_pointer_shape get_pointer_shape(struct browser_window *bw, + struct box *box, bool imagemap); +static void html_box_drag_start(struct box *box, int x, int y); + +/** + * Handle mouse tracking (including drags) in an HTML content window. + * + * \param c content of type html + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ + +void html_mouse_track(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + hlcache_handle *h = bw->current_content; + + switch (bw->drag_type) { + case DRAGGING_SELECTION: { + struct box *box; + int dir = -1; + int dx, dy; + + if (selection_dragging_start(bw->sel)) dir = 1; + + box = box_pick_text_box(h, x, y, dir, + &dx, &dy); + if (box) { + int pixel_offset; + size_t idx; + plot_font_style_t fstyle; + + font_plot_style_from_css(box->style, &fstyle); + + nsfont.font_position_in_string(&fstyle, + box->text, box->length, + dx, &idx, &pixel_offset); + + selection_track(bw->sel, mouse, + box->byte_offset + idx); + } + } + break; + + default: + html_mouse_action(c, bw, mouse, x, y); + break; + } +} + + +/** + * Handle mouse clicks and movements in an HTML content window. + * + * \param c content of type html + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + * + * This function handles both hovering and clicking. It is important that the + * code path is identical (except that hovering doesn't carry out the action), + * so that the status bar reflects exactly what will happen. Having separate + * code paths opens the possibility that an attacker will make the status bar + * show some harmless action where clicking will be harmful. + */ + +void html_mouse_action(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE; + char *title = 0; + const char *url = 0; + const char *target = 0; + char status_buffer[200]; + const char *status = 0; + gui_pointer_shape pointer = GUI_POINTER_DEFAULT; + bool imagemap = false; + int box_x = 0, box_y = 0; + int gadget_box_x = 0, gadget_box_y = 0; + int text_box_x = 0; + struct box *url_box = 0; + struct box *gadget_box = 0; + struct box *text_box = 0; + hlcache_handle *h = bw->current_content; + struct box *box; + hlcache_handle *content = h; + hlcache_handle *gadget_content = h; + struct form_control *gadget = 0; + hlcache_handle *object = NULL; + struct box *next_box; + struct box *drag_candidate = NULL; + struct scroll *scroll = NULL; + plot_font_style_t fstyle; + int scroll_mouse_x = 0, scroll_mouse_y = 0; + int padding_left, padding_right, padding_top, padding_bottom; + + + if (bw->visible_select_menu != NULL) { + box = bw->visible_select_menu->box; + box_coords(box, &box_x, &box_y); + + box_x -= box->border[LEFT].width; + box_y += box->height + box->border[BOTTOM].width + + box->padding[BOTTOM] + box->padding[TOP]; + status = form_select_mouse_action(bw->visible_select_menu, + mouse, x - box_x, y - box_y); + if (status != NULL) + browser_window_set_status(bw, status); + else { + int width, height; + form_select_get_dimensions(bw->visible_select_menu, + &width, &height); + bw->visible_select_menu = NULL; + browser_window_redraw_rect(bw, box_x, box_y, + width, height); + } + return; + } + + if (bw->scroll != NULL) { + struct browser_scroll_data *data = scroll_get_data(bw->scroll); + box = data->box; + box_coords(box, &box_x, &box_y); + if (scroll_is_horizontal(bw->scroll)) { + scroll_mouse_x = x - box_x ; + scroll_mouse_y = y - (box_y + box->padding[TOP] + + box->height + box->padding[BOTTOM] - + SCROLLBAR_WIDTH); + status = scroll_mouse_action(bw->scroll, mouse, + scroll_mouse_x, scroll_mouse_y); + } else { + scroll_mouse_x = x - (box_x + box->padding[LEFT] + + box->width + box->padding[RIGHT] - + SCROLLBAR_WIDTH); + scroll_mouse_y = y - box_y; + status = scroll_mouse_action(bw->scroll, mouse, + scroll_mouse_x, scroll_mouse_y); + } + + browser_window_set_status(bw, status); + return; + } + + bw->drag_type = DRAGGING_NONE; + + /* search the box tree for a link, imagemap, form control, or + * box with scrollbars */ + + box = html_get_box_tree(h); + + /* Consider the margins of the html page now */ + box_x = box->margin[LEFT]; + box_y = box->margin[TOP]; + + while ((next_box = box_at_point(box, x, y, &box_x, &box_y, &content)) != + NULL) { + enum css_overflow_e overflow = CSS_OVERFLOW_VISIBLE; + + box = next_box; + + if (box->style && css_computed_visibility(box->style) == + CSS_VISIBILITY_HIDDEN) + continue; + + if (box->object) + object = box->object; + + if (box->href) { + url = box->href; + target = box->target; + url_box = box; + } + + if (box->usemap) { + url = imagemap_get(content, box->usemap, + box_x, box_y, x, y, &target); + if (url) { + imagemap = true; + url_box = box; + } + } + + if (box->gadget) { + gadget_content = content; + gadget = box->gadget; + gadget_box = box; + gadget_box_x = box_x; + gadget_box_y = box_y; + if (gadget->form) + target = gadget->form->target; + } + + if (box->title) + title = box->title; + + pointer = get_pointer_shape(bw, box, false); + + if (box->style) + overflow = css_computed_overflow(box->style); + + if ((box->scroll_x != NULL || box->scroll_y != NULL) && + drag_candidate == NULL) + drag_candidate = box; + + if (box->scroll_y != NULL || box->scroll_x != NULL) { + padding_left = box_x + scroll_get_offset(box->scroll_x); + padding_right = padding_left + box->padding[LEFT] + + box->width + box->padding[RIGHT]; + padding_top = box_y + scroll_get_offset(box->scroll_y); + padding_bottom = padding_top + box->padding[TOP] + + box->height + box->padding[BOTTOM]; + + if (x > padding_left && x < padding_right && + y > padding_top && y < padding_bottom) { + /* mouse inside padding box */ + + if (box->scroll_y != NULL && x > padding_right - + SCROLLBAR_WIDTH) { + /* mouse above vertical box scroll */ + + scroll = box->scroll_y; + scroll_mouse_x = x - (padding_right - + SCROLLBAR_WIDTH); + scroll_mouse_y = y - padding_top; + break; + + } else if (box->scroll_x != NULL && + y > padding_bottom - + SCROLLBAR_WIDTH) { + /* mouse above horizontal box scroll */ + + scroll = box->scroll_x; + scroll_mouse_x = x - padding_left; + scroll_mouse_y = y - (padding_bottom - + SCROLLBAR_WIDTH); + break; + } + } + } + + if (box->text && !box->object) { + text_box = box; + text_box_x = box_x; + } + } + + /* use of box_x, box_y, or content below this point is probably a + * mistake; they will refer to the last box returned by box_at_point */ + + if (scroll) { + status = scroll_mouse_action(scroll, mouse, + scroll_mouse_x, scroll_mouse_y); + pointer = GUI_POINTER_DEFAULT; + } else if (gadget) { + switch (gadget->type) { + case GADGET_SELECT: + status = messages_get("FormSelect"); + pointer = GUI_POINTER_MENU; + if (mouse & BROWSER_MOUSE_CLICK_1 && + option_core_select_menu) { + bw->visible_select_menu = gadget; + form_open_select_menu(bw, gadget, + form_select_menu_callback, + bw); + pointer = GUI_POINTER_DEFAULT; + } else if (mouse & BROWSER_MOUSE_CLICK_1) + gui_create_form_select_menu(bw, gadget); + break; + case GADGET_CHECKBOX: + status = messages_get("FormCheckbox"); + if (mouse & BROWSER_MOUSE_CLICK_1) { + gadget->selected = !gadget->selected; + html_redraw_a_box(gadget_content, gadget_box); + } + break; + case GADGET_RADIO: + status = messages_get("FormRadio"); + if (mouse & BROWSER_MOUSE_CLICK_1) + form_radio_set(gadget_content, gadget); + break; + case GADGET_IMAGE: + if (mouse & BROWSER_MOUSE_CLICK_1) { + gadget->data.image.mx = x - gadget_box_x; + gadget->data.image.my = y - gadget_box_y; + } + /* drop through */ + case GADGET_SUBMIT: + if (gadget->form) { + snprintf(status_buffer, sizeof status_buffer, + messages_get("FormSubmit"), + gadget->form->action); + status = status_buffer; + pointer = get_pointer_shape(bw, gadget_box, + false); + if (mouse & (BROWSER_MOUSE_CLICK_1 | + BROWSER_MOUSE_CLICK_2)) + action = ACTION_SUBMIT; + } else { + status = messages_get("FormBadSubmit"); + } + break; + case GADGET_TEXTAREA: + status = messages_get("FormTextarea"); + pointer = get_pointer_shape(bw, gadget_box, false); + + if (mouse & (BROWSER_MOUSE_PRESS_1 | + BROWSER_MOUSE_PRESS_2)) { + if (text_box && selection_root(bw->sel) != + gadget_box) + selection_init(bw->sel, gadget_box); + + browser_window_textarea_click(bw, + mouse, + gadget_box, + gadget_box_x, + gadget_box_y, + x - gadget_box_x, + y - gadget_box_y); + } + + if (text_box) { + int pixel_offset; + size_t idx; + + font_plot_style_from_css(text_box->style, + &fstyle); + + nsfont.font_position_in_string(&fstyle, + text_box->text, + text_box->length, + x - gadget_box_x - text_box->x, + &idx, + &pixel_offset); + + selection_click(bw->sel, mouse, + text_box->byte_offset + idx); + + if (selection_dragging(bw->sel)) { + bw->drag_type = DRAGGING_SELECTION; + status = messages_get("Selecting"); + } else + status = content_get_status_message(h); + } + else if (mouse & BROWSER_MOUSE_PRESS_1) + selection_clear(bw->sel, true); + break; + case GADGET_TEXTBOX: + case GADGET_PASSWORD: + status = messages_get("FormTextbox"); + pointer = get_pointer_shape(bw, gadget_box, false); + + if ((mouse & BROWSER_MOUSE_PRESS_1) && + !(mouse & (BROWSER_MOUSE_MOD_1 | + BROWSER_MOUSE_MOD_2))) { + browser_window_input_click(bw, + gadget_box, + gadget_box_x, + gadget_box_y, + x - gadget_box_x, + y - gadget_box_y); + } + if (text_box) { + int pixel_offset; + size_t idx; + + if (mouse & (BROWSER_MOUSE_DRAG_1 | + BROWSER_MOUSE_DRAG_2)) + selection_init(bw->sel, gadget_box); + + font_plot_style_from_css(text_box->style, + &fstyle); + + nsfont.font_position_in_string(&fstyle, + text_box->text, + text_box->length, + x - gadget_box_x - text_box->x, + &idx, + &pixel_offset); + + selection_click(bw->sel, mouse, + text_box->byte_offset + idx); + + if (selection_dragging(bw->sel)) + bw->drag_type = DRAGGING_SELECTION; + } + else if (mouse & BROWSER_MOUSE_PRESS_1) + selection_clear(bw->sel, true); + break; + case GADGET_HIDDEN: + /* not possible: no box generated */ + break; + case GADGET_RESET: + status = messages_get("FormReset"); + break; + case GADGET_FILE: + status = messages_get("FormFile"); + break; + case GADGET_BUTTON: + /* This gadget cannot be activated */ + status = messages_get("FormButton"); + break; + } + + } else if (object && (mouse & BROWSER_MOUSE_MOD_2)) { + + if (mouse & BROWSER_MOUSE_DRAG_2) + gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, object, + bw->window); + else if (mouse & BROWSER_MOUSE_DRAG_1) + gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, object, + bw->window); + + /* \todo should have a drag-saving object msg */ + status = content_get_status_message(h); + + } else if (url) { + if (title) { + snprintf(status_buffer, sizeof status_buffer, "%s: %s", + url, title); + status = status_buffer; + } else + status = url; + + pointer = get_pointer_shape(bw, url_box, imagemap); + + if (mouse & BROWSER_MOUSE_CLICK_1 && + mouse & BROWSER_MOUSE_MOD_1) { + /* force download of link */ + browser_window_go_post(bw, url, 0, 0, false, + content_get_url(h), true, true, 0); + } else if (mouse & BROWSER_MOUSE_CLICK_2 && + mouse & BROWSER_MOUSE_MOD_1) { + gui_window_save_link(bw->window, url, title); + } else if (mouse & (BROWSER_MOUSE_CLICK_1 | + BROWSER_MOUSE_CLICK_2)) + action = ACTION_GO; + + } else { + bool done = false; + + /* frame resizing */ + if (bw->parent) { + struct browser_window *parent; + for (parent = bw->parent; parent->parent; + parent = parent->parent); + browser_window_resize_frames(parent, mouse, + x + bw->x0, y + bw->y0, + &pointer, &status, &done); + } + + /* if clicking in the main page, remove the selection from any + * text areas */ + if (!done) { + struct box *layout = html_get_box_tree(h); + + if (text_box && + (mouse & (BROWSER_MOUSE_CLICK_1 | + BROWSER_MOUSE_CLICK_2)) && + selection_root(bw->sel) != layout) + selection_init(bw->sel, layout); + + if (text_box) { + int pixel_offset; + size_t idx; + + font_plot_style_from_css(text_box->style, + &fstyle); + + nsfont.font_position_in_string(&fstyle, + text_box->text, + text_box->length, + x - text_box_x, + &idx, + &pixel_offset); + + if (selection_click(bw->sel, mouse, + text_box->byte_offset + idx)) { + /* key presses must be directed at the + * main browser window, paste text + * operations ignored */ + + if (selection_dragging(bw->sel)) { + bw->drag_type = + DRAGGING_SELECTION; + status = + messages_get("Selecting"); + } else + status = content_get_status_message(h); + + done = true; + } + } + else if (mouse & BROWSER_MOUSE_PRESS_1) + selection_clear(bw->sel, true); + } + + if (!done) { + if (title) + status = title; + else if (bw->loading_content) + status = content_get_status_message( + bw->loading_content); + else + status = content_get_status_message(h); + + if (mouse & BROWSER_MOUSE_DRAG_1) { + if (mouse & BROWSER_MOUSE_MOD_2) { + gui_drag_save_object(GUI_SAVE_COMPLETE, + h, bw->window); + } else { + if (drag_candidate == NULL) + browser_window_page_drag_start( + bw, x, y); + else { + html_box_drag_start( + drag_candidate, + x, y); + } + pointer = GUI_POINTER_MOVE; + } + } + else if (mouse & BROWSER_MOUSE_DRAG_2) { + if (mouse & BROWSER_MOUSE_MOD_2) { + gui_drag_save_object(GUI_SAVE_SOURCE, + h, bw->window); + } else { + if (drag_candidate == NULL) + browser_window_page_drag_start( + bw, x, y); + else { + html_box_drag_start( + drag_candidate, + x, y); + } + pointer = GUI_POINTER_MOVE; + } + } + } + if ((mouse & BROWSER_MOUSE_CLICK_1) && + !selection_defined(bw->sel)) { + /* ensure key presses still act on the browser window */ + browser_window_remove_caret(bw); + } + } + + + if (action == ACTION_SUBMIT || action == ACTION_GO) + bw->last_action = wallclock(); + + if (status != NULL) + browser_window_set_status(bw, status); + + browser_window_set_pointer(bw->window, pointer); + + /* deferred actions that can cause this browser_window to be destroyed + * and must therefore be done after set_status/pointer + */ + switch (action) { + case ACTION_SUBMIT: + form_submit(bw->current_content, + browser_window_find_target(bw, target, mouse), + gadget->form, gadget); + break; + case ACTION_GO: + browser_window_go(browser_window_find_target(bw, target, mouse), + url, content_get_url(h), true); + break; + case ACTION_NONE: + break; + } +} + + +gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box, + bool imagemap) +{ + gui_pointer_shape pointer; + css_computed_style *style; + enum css_cursor_e cursor; + lwc_string **cursor_uris; + bool loading; + + assert(bw); + + loading = (bw->loading_content != NULL || (bw->current_content && + content_get_status(bw->current_content) == + CONTENT_STATUS_READY)); + + if (wallclock() - bw->last_action < 100 && loading) + /* If less than 1 second since last link followed, show + * progress indicating pointer and we're loading something */ + return GUI_POINTER_PROGRESS; + + if (box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT) + style = box->children->style; + else + style = box->style; + + if (style == NULL) + return GUI_POINTER_DEFAULT; + + cursor = css_computed_cursor(style, &cursor_uris); + + switch (cursor) { + case CSS_CURSOR_AUTO: + if (box->href || (box->gadget && + (box->gadget->type == GADGET_IMAGE || + box->gadget->type == GADGET_SUBMIT)) || + imagemap) { + /* link */ + pointer = GUI_POINTER_POINT; + } else if (box->gadget && + (box->gadget->type == GADGET_TEXTBOX || + box->gadget->type == GADGET_PASSWORD || + box->gadget->type == GADGET_TEXTAREA)) { + /* text input */ + pointer = GUI_POINTER_CARET; + } else { + /* anything else */ + if (loading) { + /* loading new content */ + pointer = GUI_POINTER_PROGRESS; + } else { + pointer = GUI_POINTER_DEFAULT; + } + } + break; + case CSS_CURSOR_CROSSHAIR: + pointer = GUI_POINTER_CROSS; + break; + case CSS_CURSOR_POINTER: + pointer = GUI_POINTER_POINT; + break; + case CSS_CURSOR_MOVE: + pointer = GUI_POINTER_MOVE; + break; + case CSS_CURSOR_E_RESIZE: + pointer = GUI_POINTER_RIGHT; + break; + case CSS_CURSOR_W_RESIZE: + pointer = GUI_POINTER_LEFT; + break; + case CSS_CURSOR_N_RESIZE: + pointer = GUI_POINTER_UP; + break; + case CSS_CURSOR_S_RESIZE: + pointer = GUI_POINTER_DOWN; + break; + case CSS_CURSOR_NE_RESIZE: + pointer = GUI_POINTER_RU; + break; + case CSS_CURSOR_SW_RESIZE: + pointer = GUI_POINTER_LD; + break; + case CSS_CURSOR_SE_RESIZE: + pointer = GUI_POINTER_RD; + break; + case CSS_CURSOR_NW_RESIZE: + pointer = GUI_POINTER_LU; + break; + case CSS_CURSOR_TEXT: + pointer = GUI_POINTER_CARET; + break; + case CSS_CURSOR_WAIT: + pointer = GUI_POINTER_WAIT; + break; + case CSS_CURSOR_PROGRESS: + pointer = GUI_POINTER_PROGRESS; + break; + case CSS_CURSOR_HELP: + pointer = GUI_POINTER_HELP; + break; + default: + pointer = GUI_POINTER_DEFAULT; + break; + } + + return pointer; +} + + +/** + * Callback for in-page scrolls. + */ +void html_overflow_scroll_callback(void *client_data, + struct scroll_msg_data *scroll_data) +{ + struct browser_scroll_data *data = client_data; + struct browser_window *bw = data->bw; + struct box *box = data->box; + int x, y, box_x, box_y, diff_x, diff_y; + + + switch(scroll_data->msg) { + case SCROLL_MSG_REDRAW: + diff_x = box->padding[LEFT] + box->width + + box->padding[RIGHT] - SCROLLBAR_WIDTH; + diff_y = box->padding[TOP] + box->height + + box->padding[BOTTOM] - SCROLLBAR_WIDTH; + + box_coords(box, &box_x, &box_y); + if (scroll_is_horizontal(scroll_data->scroll)) { + x = box_x + scroll_get_offset(box->scroll_x); + y = box_y + scroll_get_offset(box->scroll_y) + + diff_y; + } else { + x = box_x + scroll_get_offset(box->scroll_x) + + diff_x; + y = box_y + scroll_get_offset(box->scroll_y); + } + browser_window_redraw_rect(bw, + x + scroll_data->x0, + y + scroll_data->y0, + scroll_data->x1 - scroll_data->x0, + scroll_data->y1 - scroll_data->y0); + break; + case SCROLL_MSG_MOVED: + html_redraw_a_box(bw->current_content, box); + break; + case SCROLL_MSG_SCROLL_START: + bw->scroll = scroll_data->scroll; + gui_window_box_scroll_start(bw->window, + scroll_data->x0, scroll_data->y0, + scroll_data->x1, scroll_data->y1); + break; + case SCROLL_MSG_SCROLL_FINISHED: + bw->scroll = NULL; + + browser_window_set_pointer(bw->window, + GUI_POINTER_DEFAULT); + break; + } +} + + +/** + * End overflow scroll scrollbar drags + * + * \param scroll scrollbar widget + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ +void html_overflow_scroll_drag_end(struct scroll *scroll, + browser_mouse_state mouse, int x, int y) +{ + int scroll_mouse_x, scroll_mouse_y, box_x, box_y; + struct browser_scroll_data *data = scroll_get_data(scroll); + struct box *box; + + box = data->box; + box_coords(box, &box_x, &box_y); + + if (scroll_is_horizontal(scroll)) { + scroll_mouse_x = x - box_x; + scroll_mouse_y = y - (box_y + box->padding[TOP] + + box->height + box->padding[BOTTOM] - + SCROLLBAR_WIDTH); + scroll_mouse_drag_end(scroll, mouse, + scroll_mouse_x, scroll_mouse_y); + } else { + scroll_mouse_x = x - (box_x + box->padding[LEFT] + + box->width + box->padding[RIGHT] - + SCROLLBAR_WIDTH); + scroll_mouse_y = y - box_y; + scroll_mouse_drag_end(scroll, mouse, + scroll_mouse_x, scroll_mouse_y); + } +} + + +/** + * End overflow scroll scrollbar drags + * + * \param h html content's high level cache entry + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ +size_t html_selection_drag_end(hlcache_handle *h, browser_mouse_state mouse, + int x, int y, int dir) +{ + int pixel_offset; + struct box *box; + int dx, dy; + int idx = 0; + + box = box_pick_text_box(h, x, y, dir, &dx, &dy); + if (box) { + plot_font_style_t fstyle; + + font_plot_style_from_css(box->style, &fstyle); + + nsfont.font_position_in_string(&fstyle, box->text, box->length, + dx, &idx, &pixel_offset); + + idx += box->byte_offset; + } + + return idx; +} + + +/** + * Start drag scrolling the contents of a box + * + * \param box the box to be scrolled + * \param x x ordinate of initial mouse position + * \param y y ordinate + */ + +void html_box_drag_start(struct box *box, int x, int y) +{ + int box_x, box_y, scroll_mouse_x, scroll_mouse_y; + + box_coords(box, &box_x, &box_y); + + if (box->scroll_x != NULL) { + scroll_mouse_x = x - box_x ; + scroll_mouse_y = y - (box_y + box->padding[TOP] + + box->height + box->padding[BOTTOM] - + SCROLLBAR_WIDTH); + scroll_start_content_drag(box->scroll_x, + scroll_mouse_x, scroll_mouse_y); + } else if (box->scroll_y != NULL) { + scroll_mouse_x = x - (box_x + box->padding[LEFT] + + box->width + box->padding[RIGHT] - + SCROLLBAR_WIDTH); + scroll_mouse_y = y - box_y; + + scroll_start_content_drag(box->scroll_y, + scroll_mouse_x, scroll_mouse_y); + } +} diff --git a/render/textplain.c b/render/textplain.c index f39a89a08..94a5cce66 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -32,6 +32,7 @@ #include "content/hlcache.h" #include "css/css.h" #include "css/utils.h" +#include "desktop/browser.h" #include "desktop/gui.h" #include "desktop/options.h" #include "desktop/plotters.h" @@ -354,6 +355,93 @@ bool textplain_clone(const struct content *old, struct content *new_content) } +/** + * Handle mouse tracking (including drags) in a TEXTPLAIN content window. + * + * \param c content of type textplain + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ + +void textplain_mouse_track(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + switch (bw->drag_type) { + + case DRAGGING_SELECTION: { + hlcache_handle *h = bw->current_content; + int dir = -1; + size_t idx; + + if (selection_dragging_start(bw->sel)) dir = 1; + + idx = textplain_offset_from_coords(h, x, y, dir); + selection_track(bw->sel, mouse, idx); + } + break; + + default: + textplain_mouse_action(c, bw, mouse, x, y); + break; + } +} + + +/** + * Handle mouse clicks and movements in a TEXTPLAIN content window. + * + * \param c content of type textplain + * \param bw browser window + * \param click type of mouse click + * \param x coordinate of mouse + * \param y coordinate of mouse + */ + +void textplain_mouse_action(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y) +{ + hlcache_handle *h = bw->current_content; + gui_pointer_shape pointer = GUI_POINTER_DEFAULT; + const char *status = 0; + size_t idx; + int dir = 0; + + bw->drag_type = DRAGGING_NONE; + + if (!bw->sel) return; + + idx = textplain_offset_from_coords(h, x, y, dir); + if (selection_click(bw->sel, mouse, idx)) { + + if (selection_dragging(bw->sel)) { + bw->drag_type = DRAGGING_SELECTION; + status = messages_get("Selecting"); + } + else + status = content_get_status_message(h); + } + else { + if (bw->loading_content) + status = content_get_status_message( + bw->loading_content); + else + status = content_get_status_message(h); + + if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { + browser_window_page_drag_start(bw, x, y); + pointer = GUI_POINTER_MOVE; + } + } + + assert(status); + + browser_window_set_status(bw, status); + browser_window_set_pointer(bw->window, pointer); +} + + /** * Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot). * diff --git a/render/textplain.h b/render/textplain.h index 61a1c0c9a..2a80f1619 100644 --- a/render/textplain.h +++ b/render/textplain.h @@ -26,6 +26,7 @@ #include #include +#include "desktop/mouse.h" struct content; struct hlcache_handle; @@ -52,6 +53,10 @@ bool textplain_create(struct content *c, const struct http_parameter *params); bool textplain_process_data(struct content *c, const char *data, unsigned int size); bool textplain_convert(struct content *c); +void textplain_mouse_track(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); +void textplain_mouse_action(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); void textplain_reformat(struct content *c, int width, int height); void textplain_destroy(struct content *c); bool textplain_redraw(struct content *c, int x, int y, diff --git a/riscos/menus.c b/riscos/menus.c index c2915349f..da0a686ad 100644 --- a/riscos/menus.c +++ b/riscos/menus.c @@ -34,12 +34,14 @@ #include "content/content.h" #include "content/hlcache.h" #include "content/urldb.h" +#include "desktop/browser.h" #include "desktop/gui.h" #include "desktop/history_core.h" #include "desktop/netsurf.h" #include "desktop/selection.h" #include "desktop/textinput.h" #include "render/box.h" +#include "render/form.h" #include "riscos/dialog.h" #include "render/form.h" #include "riscos/configure.h" @@ -710,7 +712,7 @@ void ro_gui_menu_selection(wimp_selection *selection) assert(g); if (selection->items[0] >= 0) { - browser_window_form_select(g->bw, + form_select_process_selection(g->bw->current_content, gui_form_select_control, selection->items[0]); } diff --git a/riscos/window.c b/riscos/window.c index 795429e03..198563059 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -46,6 +46,7 @@ #include "css/css.h" #include "desktop/browser.h" #include "desktop/frames.h" +#include "desktop/mouse.h" #include "desktop/plotters.h" #include "desktop/textinput.h" #include "desktop/tree.h" diff --git a/windows/gui.c b/windows/gui.c index 7dfa7579c..7f2519196 100644 --- a/windows/gui.c +++ b/windows/gui.c @@ -37,9 +37,10 @@ #include "css/utils.h" #include "desktop/gui.h" #include "desktop/history_core.h" -#include "desktop/plotters.h" +#include "desktop/mouse.h" #include "desktop/netsurf.h" #include "desktop/options.h" +#include "desktop/plotters.h" #include "desktop/save_complete.h" #include "desktop/selection.h" #include "desktop/textinput.h" -- cgit v1.2.3