diff --git a/content/content.h b/content/content.h index 7781ba9b8..2ae0b38be 100644 --- a/content/content.h +++ b/content/content.h @@ -78,7 +78,8 @@ typedef enum { CONTENT_MSG_SCROLL, /**< Request to scroll content */ CONTENT_MSG_DRAGSAVE, /**< Allow drag saving of content */ CONTENT_MSG_SAVELINK, /**< Allow URL to be saved */ - CONTENT_MSG_POINTER /**< Wants a specific mouse pointer set */ + CONTENT_MSG_POINTER, /**< Wants a specific mouse pointer set */ + CONTENT_MSG_DRAG /**< A drag started or ended */ } content_msg; /** RFC5988 metadata link */ @@ -152,14 +153,15 @@ union content_msg_data { } savelink; /** CONTENT_MSG_POINTER - Mouse pointer to set */ browser_pointer_shape pointer; - /** CONTENT_MSG_PASTE - Content requests that clipboard is pasted */ + /** CONTENT_MSG_DRAG - Drag start or end */ struct { - /* TODO: Get rid of these coords. - * browser_window_paste_text doesn't take coords, but - * RISC OS front end is doing something different. */ - int x; - int y; - } paste; + enum { + CONTENT_DRAG_NONE, + CONTENT_DRAG_SCROLL, + CONTENT_DRAG_SELECTION + } type; + const struct rect *rect; + } drag; }; /** parameters to content redraw */ diff --git a/desktop/browser.c b/desktop/browser.c index 6a1688192..836f594e6 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -1545,6 +1545,25 @@ nserror browser_window_callback(hlcache_handle *c, browser_window_set_pointer(bw, event->data.pointer); break; + case CONTENT_MSG_DRAG: + { + browser_drag_type bdt = DRAGGING_NONE; + + switch (event->data.drag.type) { + case CONTENT_DRAG_NONE: + bdt = DRAGGING_NONE; + break; + case CONTENT_DRAG_SCROLL: + bdt = DRAGGING_SELECTION; + break; + case CONTENT_DRAG_SELECTION: + bdt = DRAGGING_CONTENT_SCROLLBAR; + break; + } + browser_window_set_drag_type(bw, bdt, event->data.drag.rect); + } + break; + default: assert(0); } diff --git a/desktop/browser.h b/desktop/browser.h index 1c7772d0d..f3c68fa09 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -57,8 +57,6 @@ typedef enum { DRAGGING_SCR_X, DRAGGING_SCR_Y, DRAGGING_CONTENT_SCROLLBAR, - DRAGGING_CONTENT_TEXTAREA_SCROLLBAR, - DRAGGING_CONTENT_TEXTAREA_SELECTION, DRAGGING_OTHER } browser_drag_type; diff --git a/render/box_textarea.c b/render/box_textarea.c index f5a45ec94..2bbeab31e 100644 --- a/render/box_textarea.c +++ b/render/box_textarea.c @@ -28,6 +28,7 @@ #include "render/box_textarea.h" #include "render/font.h" #include "render/form.h" +#include "utils/log.h" static bool box_textarea_browser_caret_callback(struct browser_window *bw, @@ -124,23 +125,20 @@ static bool box_textarea_browser_paste_callback(struct browser_window *bw, static void box_textarea_callback(void *data, struct textarea_msg *msg) { struct form_textarea_data *d = data; - struct content *c = (struct content *)d->html; struct html_content *html = d->html; struct form_control *gadget = d->gadget; struct box *box = gadget->box; - union content_msg_data msg_data; switch (msg->type) { case TEXTAREA_MSG_DRAG_REPORT: if (msg->data.drag == TEXTAREA_DRAG_NONE) { /* Textarea drag finished */ - html->textarea = NULL; + html_drag_type drag_type = HTML_DRAG_NONE; + union html_drag_owner drag_owner; + drag_owner.no_owner = true; - browser_window_set_drag_type(html->bw, - DRAGGING_NONE, NULL); - - msg_data.pointer = BROWSER_POINTER_AUTO; - content_broadcast(c, CONTENT_MSG_POINTER, msg_data); + html_set_drag_type(d->html, drag_type, drag_owner, + NULL); } else { /* Textarea drag started */ struct rect rect = { @@ -149,16 +147,25 @@ static void box_textarea_callback(void *data, struct textarea_msg *msg) .x1 = INT_MAX, .y1 = INT_MAX }; - browser_drag_type bdt; + html_drag_type drag_type; + union html_drag_owner drag_owner; + drag_owner.textarea = box; - if (msg->data.drag == TEXTAREA_DRAG_SCROLLBAR) - bdt = DRAGGING_CONTENT_TEXTAREA_SCROLLBAR; - else - bdt = DRAGGING_CONTENT_TEXTAREA_SELECTION; + switch (msg->data.drag) { + case TEXTAREA_DRAG_SCROLLBAR: + drag_type = HTML_DRAG_TEXTAREA_SCROLLBAR; + break; + case TEXTAREA_DRAG_SELECTION: + drag_type = HTML_DRAG_TEXTAREA_SELECTION; + break; + default: + LOG(("Drag type not handled.")); + assert(0); + break; + } - browser_window_set_drag_type(html->bw, bdt, &rect); - - html->textarea = msg->ta; + html_set_drag_type(d->html, drag_type, drag_owner, + &rect); } break; diff --git a/render/html.c b/render/html.c index 85e377095..c135db198 100644 --- a/render/html.c +++ b/render/html.c @@ -343,8 +343,8 @@ html_create_html_data(html_content *c, const http_parameter *params) c->iframe = NULL; c->page = NULL; c->font_func = &nsfont; - c->scrollbar = NULL; - c->textarea = NULL; + c->drag_type = HTML_DRAG_NONE; + c->drag_owner.no_owner = true; c->scripts_count = 0; c->scripts = NULL; c->jscontext = NULL; @@ -1308,6 +1308,29 @@ html_object_callback(hlcache_handle *object, content_broadcast(&c->base, event->type, event->data); break; + case CONTENT_MSG_DRAG: + { + html_drag_type drag_type = HTML_DRAG_NONE; + union html_drag_owner drag_owner; + drag_owner.content = box; + + switch (event->data.drag.type) { + case CONTENT_DRAG_NONE: + drag_type = HTML_DRAG_NONE; + drag_owner.no_owner = true; + break; + case CONTENT_DRAG_SCROLL: + drag_type = HTML_DRAG_CONTENT_SCROLL; + break; + case CONTENT_DRAG_SELECTION: + drag_type = HTML_DRAG_CONTENT_SELECTION; + break; + } + html_set_drag_type(c, drag_type, drag_owner, + event->data.drag.rect); + } + break; + default: assert(0); } diff --git a/render/html_interaction.c b/render/html_interaction.c index b66868257..c33d654a7 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -224,9 +224,10 @@ void html_mouse_track(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { html_content *html = (html_content*) c; - browser_drag_type drag_type = browser_window_get_drag_type(bw); + union html_drag_owner drag_owner; - if (drag_type == DRAGGING_SELECTION && !mouse) { + if (html->drag_type == HTML_DRAG_SELECTION && !mouse) { + /* End of selection drag */ int dir = -1; size_t idx; @@ -238,40 +239,37 @@ void html_mouse_track(struct content *c, struct browser_window *bw, if (idx != 0) selection_track(&html->sel, mouse, idx); - browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); + drag_owner.no_owner = true; + html_set_drag_type(html, HTML_DRAG_NONE, drag_owner, NULL); } - switch (drag_type) { - case DRAGGING_SELECTION: { - struct box *box; - int dir = -1; - int dx, dy; + if (html->drag_type == HTML_DRAG_SELECTION) { + /* Selection drag */ + struct box *box; + int dir = -1; + int dx, dy; - if (selection_dragging_start(&html->sel)) - dir = 1; + if (selection_dragging_start(&html->sel)) + dir = 1; - box = box_pick_text_box(html, x, y, dir, &dx, &dy); + box = box_pick_text_box(html, x, y, dir, &dx, &dy); - if (box) { - int pixel_offset; - size_t idx; - plot_font_style_t fstyle; + if (box != NULL) { + int pixel_offset; + size_t idx; + plot_font_style_t fstyle; - font_plot_style_from_css(box->style, &fstyle); + font_plot_style_from_css(box->style, &fstyle); - nsfont.font_position_in_string(&fstyle, - box->text, box->length, - dx, &idx, &pixel_offset); + nsfont.font_position_in_string(&fstyle, + box->text, box->length, + dx, &idx, &pixel_offset); - selection_track(&html->sel, mouse, - box->byte_offset + idx); - } + selection_track(&html->sel, mouse, + box->byte_offset + idx); } - break; - - default: - html_mouse_action(c, bw, mouse, x, y); - break; + } else { + html_mouse_action(c, bw, mouse, x, y); } } @@ -356,29 +354,30 @@ void html_mouse_action(struct content *c, struct browser_window *bw, return; } - if (!mouse && html->scrollbar != NULL) { - /* drag end: scrollbar */ - html_overflow_scroll_drag_end(html->scrollbar, mouse, x, y); - } + if (html->drag_type == HTML_DRAG_SCROLLBAR) { + struct scrollbar *scr = html->drag_owner.scrollbar; + struct html_scrollbar_data *data = scrollbar_get_data(scr); + + if (!mouse) { + /* drag end: scrollbar */ + html_overflow_scroll_drag_end(scr, mouse, x, y); + } - if (html->scrollbar != NULL) { - struct html_scrollbar_data *data = - scrollbar_get_data(html->scrollbar); box = data->box; box_coords(box, &box_x, &box_y); - if (scrollbar_is_horizontal(html->scrollbar)) { + if (scrollbar_is_horizontal(scr)) { scroll_mouse_x = x - box_x ; scroll_mouse_y = y - (box_y + box->padding[TOP] + box->height + box->padding[BOTTOM] - SCROLLBAR_WIDTH); - status = scrollbar_mouse_action(html->scrollbar, mouse, + status = scrollbar_mouse_action(scr, 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 = scrollbar_mouse_action(html->scrollbar, mouse, + status = scrollbar_mouse_action(scr, mouse, scroll_mouse_x, scroll_mouse_y); } @@ -387,8 +386,35 @@ void html_mouse_action(struct content *c, struct browser_window *bw, return; } + if (html->drag_type == HTML_DRAG_TEXTAREA_SELECTION || + html->drag_type == HTML_DRAG_TEXTAREA_SCROLLBAR) { + box = html->drag_owner.textarea; + assert(box->gadget != NULL); + assert(box->gadget->type == GADGET_TEXTAREA || + box->gadget->type == GADGET_PASSWORD || + box->gadget->type == GADGET_TEXTBOX); + + box_coords(box, &box_x, &box_y); + textarea_mouse_action(box->gadget->data.text.ta, mouse, + x - box_x, y - box_y); + + /* TODO: Set appropriate statusbar message */ + return; + } + + if (html->drag_type == HTML_DRAG_CONTENT_SELECTION || + html->drag_type == HTML_DRAG_CONTENT_SCROLL) { + box = html->drag_owner.content; + assert(box->object != NULL); + + box_coords(box, &box_x, &box_y); + content_mouse_track(box->object, bw, mouse, + x - box_x, y - box_y); + return; + } + /* Content related drags handled by now */ - browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); + assert(html->drag_type == HTML_DRAG_NONE); /* search the box tree for a link, imagemap, form control, or * box with scrollbars @@ -734,11 +760,16 @@ void html_mouse_action(struct content *c, struct browser_window *bw, /* key presses must be directed at the * main browser window, paste text * operations ignored */ + html_drag_type drag_type; + union html_drag_owner drag_owner; if (selection_dragging(&html->sel)) { - browser_window_set_drag_type(bw, - DRAGGING_SELECTION, - NULL); + drag_type = HTML_DRAG_SELECTION; + drag_owner.no_owner = true; + html_set_drag_type(html, + drag_type, + drag_owner, + NULL); status = messages_get( "Selecting"); } @@ -845,35 +876,34 @@ void html_overflow_scroll_callback(void *client_data, html_content *html = (html_content *)data->c; struct box *box = data->box; union content_msg_data msg_data; + html_drag_type drag_type; + union html_drag_owner drag_owner; switch(scrollbar_data->msg) { - case SCROLLBAR_MSG_MOVED: - html__redraw_a_box(html, box); - break; - case SCROLLBAR_MSG_SCROLL_START: - { - struct rect rect = { - .x0 = scrollbar_data->x0, - .y0 = scrollbar_data->y0, - .x1 = scrollbar_data->x1, - .y1 = scrollbar_data->y1 - }; - browser_window_set_drag_type(html->bw, - DRAGGING_CONTENT_SCROLLBAR, &rect); + case SCROLLBAR_MSG_MOVED: + html__redraw_a_box(html, box); + break; + case SCROLLBAR_MSG_SCROLL_START: + { + struct rect rect = { + .x0 = scrollbar_data->x0, + .y0 = scrollbar_data->y0, + .x1 = scrollbar_data->x1, + .y1 = scrollbar_data->y1 + }; + drag_type = HTML_DRAG_SCROLLBAR; + drag_owner.scrollbar = scrollbar_data->scrollbar; + html_set_drag_type(html, drag_type, drag_owner, &rect); + } + break; + case SCROLLBAR_MSG_SCROLL_FINISHED: + drag_type = HTML_DRAG_NONE; + drag_owner.no_owner = true; + html_set_drag_type(html, drag_type, drag_owner, NULL); - html->scrollbar = scrollbar_data->scrollbar; - } - break; - case SCROLLBAR_MSG_SCROLL_FINISHED: - html->scrollbar = NULL; - - browser_window_set_drag_type(html->bw, - DRAGGING_NONE, NULL); - - msg_data.pointer = BROWSER_POINTER_AUTO; - content_broadcast(data->c, CONTENT_MSG_POINTER, - msg_data); - break; + msg_data.pointer = BROWSER_POINTER_AUTO; + content_broadcast(data->c, CONTENT_MSG_POINTER, msg_data); + break; } } @@ -912,3 +942,39 @@ void html_overflow_scroll_drag_end(struct scrollbar *scrollbar, scroll_mouse_x, scroll_mouse_y); } } + +void html_set_drag_type(html_content *html, html_drag_type drag_type, + union html_drag_owner drag_owner, const struct rect *rect) +{ + union content_msg_data msg_data; + + assert(html != NULL); + + html->drag_type = drag_type; + html->drag_owner = drag_owner; + + switch (drag_type) { + case HTML_DRAG_NONE: + assert(drag_owner.no_owner == true); + msg_data.drag.type = CONTENT_DRAG_NONE; + break; + + case HTML_DRAG_SCROLLBAR: + case HTML_DRAG_TEXTAREA_SCROLLBAR: + case HTML_DRAG_CONTENT_SCROLL: + msg_data.drag.type = CONTENT_DRAG_SCROLL; + break; + + case HTML_DRAG_SELECTION: + assert(drag_owner.no_owner == true); + /* Fall through */ + case HTML_DRAG_TEXTAREA_SELECTION: + case HTML_DRAG_CONTENT_SELECTION: + msg_data.drag.type = CONTENT_DRAG_SELECTION; + break; + } + msg_data.drag.rect = rect; + + /* Inform the content's drag status change */ + content_broadcast((struct content *)html, CONTENT_MSG_DRAG, msg_data); +} diff --git a/render/html_internal.h b/render/html_internal.h index d09121675..85f3f8a70 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -27,6 +27,22 @@ #include "desktop/selection.h" #include "render/html.h" +typedef enum { + HTML_DRAG_NONE, /** No drag */ + HTML_DRAG_SELECTION, /** Own; Text selection */ + HTML_DRAG_SCROLLBAR, /** Not own; drag in scrollbar widget */ + HTML_DRAG_TEXTAREA_SELECTION, /** Not own; drag in textarea widget */ + HTML_DRAG_TEXTAREA_SCROLLBAR, /** Not own; drag in textarea widget */ + HTML_DRAG_CONTENT_SELECTION, /** Not own; drag in child content */ + HTML_DRAG_CONTENT_SCROLL /** Not own; drag in child content */ +} html_drag_type; +union html_drag_owner { + bool no_owner; + struct box *content; + struct scrollbar *scrollbar; + struct box *textarea; +}; /**< For drags we don't own */ + /** Data specific to CONTENT_HTML. */ typedef struct html_content { struct content base; @@ -98,13 +114,10 @@ typedef struct html_content { * object within a page. */ struct html_content *page; - /** Scrollbar capturing all mouse events, updated to any active HTML - * scrollbar, or NULL when no scrollbar drags active */ - struct scrollbar *scrollbar; - - /** Textarea capturing all mouse events, updated to any active HTML - * textarea, or NULL when no textarea drags active */ - struct textarea *textarea; + /* Current drag type */ + html_drag_type drag_type; + /** Widget capturing all mouse events */ + union html_drag_owner drag_owner; /** Open core-handled form SELECT menu, * or NULL if none currently open. */ @@ -128,6 +141,9 @@ void html_set_status(html_content *c, const char *extra); void html__redraw_a_box(html_content *html, struct box *box); +void html_set_drag_type(html_content *html, html_drag_type drag_type, + union html_drag_owner drag_owner, const struct rect *rect); + struct browser_window *html_get_browser_window(struct content *c); struct search_context *html_get_search(struct content *c); void html_set_search(struct content *c, struct search_context *s);