summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rw-r--r--render/box_textarea.c66
-rw-r--r--render/box_textarea.h11
-rw-r--r--render/html.c112
-rw-r--r--render/html.h1
-rw-r--r--render/html_interaction.c359
-rw-r--r--render/html_internal.h70
-rw-r--r--render/textplain.c49
7 files changed, 568 insertions, 100 deletions
diff --git a/render/box_textarea.c b/render/box_textarea.c
index 3109904d0..3d9838fa1 100644
--- a/render/box_textarea.c
+++ b/render/box_textarea.c
@@ -31,14 +31,11 @@
#include "utils/log.h"
-static bool box_textarea_browser_caret_callback(struct browser_window *bw,
- uint32_t key, void *p1, void *p2)
+bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
{
- struct box *box = p1;
struct form_control *gadget = box->gadget;
struct textarea *ta = gadget->data.text.ta;
struct form* form = box->gadget->form;
- html_content *html = p2;
struct content *c = (struct content *) html;
assert(ta != NULL);
@@ -104,21 +101,6 @@ static bool box_textarea_browser_caret_callback(struct browser_window *bw,
}
-static void box_textarea_browser_move_callback(struct browser_window *bw,
- void *p1, void *p2)
-{
-}
-
-
-static bool box_textarea_browser_paste_callback(struct browser_window *bw,
- const char *utf8, unsigned utf8_len, bool last,
- void *p1, void *p2)
-{
- printf("AWWOOOOOGA!\n");
- return true;
-}
-
-
/**
* Callback for html form textareas.
*/
@@ -175,23 +157,43 @@ static void box_textarea_callback(void *data, struct textarea_msg *msg)
html__redraw_a_box(html, box);
break;
- case TEXTAREA_MSG_MOVED_CARET:
+ case TEXTAREA_MSG_SELECTION_REPORT:
+ if (msg->data.selection.have_selection) {
+ /* Textarea now has a selection */
+ union html_selection_owner sel_owner;
+ sel_owner.textarea = box;
+
+ html_set_selection(d->html, HTML_SELECTION_TEXTAREA,
+ sel_owner,
+ msg->data.selection.read_only);
+ } else {
+ /* The textarea now has no selection */
+ union html_selection_owner sel_owner;
+ sel_owner.none = true;
+
+ html_set_selection(d->html, HTML_SELECTION_NONE,
+ sel_owner, true);
+ }
+ break;
+
+ case TEXTAREA_MSG_CARET_UPDATE:
if (html->bw == NULL)
break;
- if (msg->data.caret.hidden) {
- browser_window_remove_caret(html->bw);
+ if (msg->data.caret.type == TEXTAREA_CARET_HIDE) {
+ union html_focus_owner focus_owner;
+ focus_owner.textarea = box;
+ html_set_focus(d->html, HTML_FOCUS_TEXTAREA,
+ focus_owner, true, 0, 0, 0, NULL);
} else {
- int x, y;
- box_coords(box, &x, &y);
- browser_window_place_caret(html->bw,
- x + msg->data.caret.x,
- y + msg->data.caret.y,
- msg->data.caret.height,
- box_textarea_browser_caret_callback,
- box_textarea_browser_paste_callback,
- box_textarea_browser_move_callback,
- box, html);
+ union html_focus_owner focus_owner;
+ focus_owner.textarea = box;
+ html_set_focus(d->html, HTML_FOCUS_TEXTAREA,
+ focus_owner, false,
+ msg->data.caret.pos.x,
+ msg->data.caret.pos.y,
+ msg->data.caret.pos.height,
+ msg->data.caret.pos.clip);
}
break;
}
diff --git a/render/box_textarea.h b/render/box_textarea.h
index 30414e816..a7a377076 100644
--- a/render/box_textarea.h
+++ b/render/box_textarea.h
@@ -41,4 +41,15 @@ struct dom_node;
bool box_textarea_create_textarea(html_content *html,
struct box *box, struct dom_node *node);
+
+/**
+ * Handle form textarea keypress input
+ *
+ * \param html html content object
+ * \param box box with textarea widget
+ * \param key keypress
+ * \return true iff keypress handled
+ */
+bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key);
+
#endif
diff --git a/render/html.c b/render/html.c
index 4fc152a84..e697c9f12 100644
--- a/render/html.c
+++ b/render/html.c
@@ -346,6 +346,10 @@ html_create_html_data(html_content *c, const http_parameter *params)
c->font_func = &nsfont;
c->drag_type = HTML_DRAG_NONE;
c->drag_owner.no_owner = true;
+ c->selection_type = HTML_SELECTION_NONE;
+ c->selection_owner.none = true;
+ c->focus_type = HTML_FOCUS_SELF;
+ c->focus_owner.self = true;
c->scripts_count = 0;
c->scripts = NULL;
c->jscontext = NULL;
@@ -1309,6 +1313,28 @@ html_object_callback(hlcache_handle *object,
content_broadcast(&c->base, event->type, event->data);
break;
+ case CONTENT_MSG_CARET:
+ {
+ union html_focus_owner focus_owner;
+ focus_owner.content = box;
+
+ switch (event->data.caret.type) {
+ case CONTENT_CARET_REMOVE:
+ case CONTENT_CARET_HIDE:
+ html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
+ true, 0, 0, 0, NULL);
+ break;
+ case CONTENT_CARET_SET_POS:
+ html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
+ false, event->data.caret.pos.x,
+ event->data.caret.pos.y,
+ event->data.caret.pos.height,
+ event->data.caret.pos.clip);
+ break;
+ }
+ }
+ break;
+
case CONTENT_MSG_DRAG:
{
html_drag_type drag_type = HTML_DRAG_NONE;
@@ -1332,6 +1358,23 @@ html_object_callback(hlcache_handle *object,
}
break;
+ case CONTENT_MSG_SELECTION:
+ {
+ html_selection_type sel_type;
+ union html_selection_owner sel_owner;
+
+ if (event->data.selection.selection) {
+ sel_type = HTML_SELECTION_CONTENT;
+ sel_owner.content = box;
+ } else {
+ sel_type = HTML_SELECTION_NONE;
+ sel_owner.none = true;
+ }
+ html_set_selection(c, sel_type, sel_owner,
+ event->data.selection.read_only);
+ }
+ break;
+
default:
assert(0);
}
@@ -1514,6 +1557,10 @@ html_convert_css_callback(hlcache_handle *css,
}
break;
+ case CONTENT_MSG_POINTER:
+ /* Really don't want this to continue after the switch */
+ return NSERROR_OK;
+
default:
assert(0);
}
@@ -2513,8 +2560,13 @@ html_open(struct content *c,
html->bw = bw;
html->page = (html_content *) page;
+ html->drag_type = HTML_DRAG_NONE;
+ html->drag_owner.no_owner = true;
+
/* text selection */
selection_init(&html->sel, html->layout);
+ html->selection_type = HTML_SELECTION_NONE;
+ html->selection_owner.none = true;
for (object = html->object_list; object != NULL; object = next) {
next = object->next;
@@ -2541,6 +2593,8 @@ static void html_close(struct content *c)
html_content *html = (html_content *) c;
struct content_html_object *object, *next;
+ selection_clear(&html->sel, false);
+
if (html->search != NULL)
search_destroy_context(html->search);
@@ -2567,11 +2621,63 @@ static void html_close(struct content *c)
* Return an HTML content's selection context
*/
-static struct selection *html_get_selection(struct content *c)
+static void html_clear_selection(struct content *c)
+{
+ html_content *html = (html_content *) c;
+
+ switch (html->selection_type) {
+ case HTML_SELECTION_NONE:
+ /* Nothing to do */
+ assert(html->selection_owner.none == true);
+ break;
+ case HTML_SELECTION_TEXTAREA:
+ textarea_clear_selection(html->selection_owner.textarea->
+ gadget->data.text.ta);
+ break;
+ case HTML_SELECTION_SELF:
+ assert(html->selection_owner.none == false);
+ selection_clear(&html->sel, true);
+ break;
+ case HTML_SELECTION_CONTENT:
+ content_clear_selection(html->selection_owner.content->object);
+ break;
+ default:
+ break;
+ }
+
+ /* There is no selection now. */
+ html->selection_type = HTML_SELECTION_NONE;
+ html->selection_owner.none = true;
+}
+
+
+/**
+ * Return an HTML content's selection context
+ */
+
+static char *html_get_selection(struct content *c)
{
html_content *html = (html_content *) c;
- return &html->sel;
+ switch (html->selection_type) {
+ case HTML_SELECTION_TEXTAREA:
+ return textarea_get_selection(html->selection_owner.textarea->
+ gadget->data.text.ta);
+ case HTML_SELECTION_SELF:
+ assert(html->selection_owner.none == false);
+ return selection_get_copy(&html->sel);
+ case HTML_SELECTION_CONTENT:
+ return content_get_selection(
+ html->selection_owner.content->object);
+ case HTML_SELECTION_NONE:
+ /* Nothing to do */
+ assert(html->selection_owner.none == true);
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
}
@@ -3214,10 +3320,12 @@ static const content_handler html_content_handler = {
.stop = html_stop,
.mouse_track = html_mouse_track,
.mouse_action = html_mouse_action,
+ .keypress = html_keypress,
.redraw = html_redraw,
.open = html_open,
.close = html_close,
.get_selection = html_get_selection,
+ .clear_selection = html_clear_selection,
.get_contextual_content = html_get_contextual_content,
.scroll_at_point = html_scroll_at_point,
.drop_file_at_point = html_drop_file_at_point,
diff --git a/render/html.h b/render/html.h
index a9f7967f6..c208f47d6 100644
--- a/render/html.h
+++ b/render/html.h
@@ -50,6 +50,7 @@ struct textarea;
struct scrollbar;
struct scrollbar_msg_data;
struct search_context;
+struct selection;
/**
* Container for stylesheets used by an HTML document
diff --git a/render/html_interaction.c b/render/html_interaction.c
index 3f1bee475..d734c6b9f 100644
--- a/render/html_interaction.c
+++ b/render/html_interaction.c
@@ -223,54 +223,7 @@ static size_t html_selection_drag_end(struct html_content *html,
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;
- union html_drag_owner drag_owner;
-
- if (html->drag_type == HTML_DRAG_SELECTION && !mouse) {
- /* End of selection drag */
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&html->sel))
- dir = 1;
-
- idx = html_selection_drag_end(html, mouse, x, y, dir);
-
- if (idx != 0)
- selection_track(&html->sel, mouse, idx);
-
- drag_owner.no_owner = true;
- html_set_drag_type(html, HTML_DRAG_NONE, drag_owner, NULL);
- }
-
- 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;
-
- box = box_pick_text_box(html, x, y, dir, &dx, &dy);
-
- if (box != NULL) {
- 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(&html->sel, mouse,
- box->byte_offset + idx);
- }
- } else {
- html_mouse_action(c, bw, mouse, x, y);
- }
+ html_mouse_action(c, bw, mouse, x, y);
}
@@ -323,6 +276,11 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
browser_drag_type drag_type = browser_window_get_drag_type(bw);
union content_msg_data msg_data;
struct dom_node *node = NULL;
+ union html_drag_owner drag_owner;
+ union html_selection_owner sel_owner;
+ bool click = mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 |
+ BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2);
if (drag_type != DRAGGING_NONE && !mouse &&
html->visible_select_menu != NULL) {
@@ -349,7 +307,55 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
&width, &height);
html->visible_select_menu = NULL;
browser_window_redraw_rect(bw, box_x, box_y,
- width, height);
+ width, height);
+ }
+ return;
+ }
+
+ if (html->drag_type == HTML_DRAG_SELECTION) {
+ /* Selection drag */
+
+ if (!mouse) {
+ /* End of selection drag */
+ int dir = -1;
+ size_t idx;
+
+ if (selection_dragging_start(&html->sel))
+ dir = 1;
+
+ idx = html_selection_drag_end(html, mouse, x, y, dir);
+
+ if (idx != 0)
+ selection_track(&html->sel, mouse, idx);
+
+ drag_owner.no_owner = true;
+ html_set_drag_type(html, HTML_DRAG_NONE,
+ drag_owner, NULL);
+ return;
+ }
+
+ struct box *box;
+ int dir = -1;
+ int dx, dy;
+
+ if (selection_dragging_start(&html->sel))
+ dir = 1;
+
+ box = box_pick_text_box(html, x, y, dir, &dx, &dy);
+
+ if (box != NULL) {
+ 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(&html->sel, mouse,
+ box->byte_offset + idx);
}
return;
}
@@ -413,6 +419,16 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
return;
}
+ if (html->drag_type == HTML_DRAG_CONTENT_SELECTION) {
+ 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 */
assert(html->drag_type == HTML_DRAG_NONE);
@@ -536,7 +552,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/* mouse inside padding box */
if ((box->scroll_y != NULL) &&
- (x > (padding_right - SCROLLBAR_WIDTH))) {
+ (x > (padding_right -
+ SCROLLBAR_WIDTH))) {
/* mouse above vertical box scroll */
scrollbar = box->scroll_y;
@@ -546,7 +563,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
break;
} else if ((box->scroll_x != NULL) &&
- (y > (padding_bottom - SCROLLBAR_WIDTH))) {
+ (y > (padding_bottom -
+ SCROLLBAR_WIDTH))) {
/* mouse above horizontal box scroll */
scrollbar = box->scroll_x;
@@ -628,6 +646,15 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
pointer = get_pointer_shape(gadget_box, false);
+ if (click && (html->selection_type !=
+ HTML_SELECTION_TEXTAREA ||
+ html->selection_owner.textarea !=
+ gadget_box)) {
+ sel_owner.none = true;
+ html_set_selection(html, HTML_SELECTION_NONE,
+ sel_owner, true);
+ }
+
textarea_mouse_action(gadget->data.text.ta, mouse,
x - gadget_box_x, y - gadget_box_y);
break;
@@ -679,6 +706,14 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
x - pos_x, y - pos_y);
}
} else if (html_object_box) {
+
+ if (click && (html->selection_type != HTML_SELECTION_CONTENT ||
+ html->selection_owner.content !=
+ html_object_box)) {
+ sel_owner.none = true;
+ html_set_selection(html, HTML_SELECTION_NONE,
+ sel_owner, true);
+ }
if (mouse & BROWSER_MOUSE_CLICK_1 ||
mouse & BROWSER_MOUSE_CLICK_2) {
content_mouse_action(html_object_box->object,
@@ -738,11 +773,18 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/* if clicking in the main page, remove the selection from any
* text areas */
if (!done) {
- struct box *layout = html->layout;
-
- if (mouse && (mouse < BROWSER_MOUSE_MOD_1) &&
- selection_root(&html->sel) != layout) {
- selection_init(&html->sel, layout);
+
+ if (click && html->focus_type != HTML_FOCUS_SELF) {
+ union html_focus_owner fo;
+ fo.self = true;
+ html_set_focus(html, HTML_FOCUS_SELF, fo,
+ true, 0, 0, 0, NULL);
+ }
+ if (click && html->selection_type !=
+ HTML_SELECTION_SELF) {
+ sel_owner.none = true;
+ html_set_selection(html, HTML_SELECTION_NONE,
+ sel_owner, true);
}
if (text_box) {
@@ -781,8 +823,24 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
done = true;
}
- } else if (mouse & BROWSER_MOUSE_PRESS_1)
+ } else if (mouse & BROWSER_MOUSE_PRESS_1) {
+ union html_selection_owner sel_owner;
+ sel_owner.none = true;
selection_clear(&html->sel, true);
+ }
+
+ if (selection_defined(&html->sel)) {
+ sel_owner.none = false;
+ html_set_selection(html, HTML_SELECTION_SELF,
+ sel_owner,
+ selection_read_only(
+ &html->sel));
+ } else if (click && html->selection_type !=
+ HTML_SELECTION_NONE) {
+ sel_owner.none = true;
+ html_set_selection(html, HTML_SELECTION_NONE,
+ sel_owner, true);
+ }
}
if (!done) {
@@ -832,7 +890,10 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
}
if (mouse && mouse < BROWSER_MOUSE_MOD_1) {
/* ensure key presses still act on the browser window */
- browser_window_remove_caret(bw);
+ union html_focus_owner fo;
+ fo.self = true;
+ html_set_focus(html, HTML_FOCUS_SELF, fo,
+ true, 0, 0, 0, NULL);
}
}
@@ -876,6 +937,61 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/**
+ * Handle keypresses.
+ *
+ * \param c content of type CONTENT_TEXTPLAIN
+ * \param key The UCS4 character codepoint
+ * \return true if key handled, false otherwise
+ */
+
+bool html_keypress(struct content *c, uint32_t key)
+{
+ html_content *html = (html_content *) c;
+ struct selection *sel = &html->sel;
+ struct box *box;
+
+ switch (html->focus_type) {
+ case HTML_FOCUS_CONTENT:
+ box = html->focus_owner.content;
+ return content_keypress(box->object, key);
+
+ case HTML_FOCUS_TEXTAREA:
+ box = html->focus_owner.textarea;
+ return textarea_keypress(box->gadget->data.text.ta, key);
+
+ default:
+ /* Deal with it below */
+ break;
+ }
+
+ switch (key) {
+ case KEY_COPY_SELECTION:
+ selection_copy_to_clipboard(sel);
+ return true;
+
+ case KEY_CLEAR_SELECTION:
+ selection_clear(sel, true);
+ return true;
+
+ case KEY_SELECT_ALL:
+ selection_select_all(sel);
+ return true;
+
+ case KEY_ESCAPE:
+ if (selection_defined(sel)) {
+ selection_clear(sel, true);
+ return true;
+ }
+
+ /* if there's no selection, leave Escape for the caller */
+ return false;
+ }
+
+ return false;
+}
+
+
+/**
* Callback for in-page scrollbars.
*/
void html_overflow_scroll_callback(void *client_data,
@@ -985,6 +1101,131 @@ void html_set_drag_type(html_content *html, html_drag_type drag_type,
}
msg_data.drag.rect = rect;
- /* Inform the content's drag status change */
+ /* Inform of the content's drag status change */
content_broadcast((struct content *)html, CONTENT_MSG_DRAG, msg_data);
}
+
+/* Documented in html_internal.h */
+void html_set_focus(html_content *html, html_focus_type focus_type,
+ union html_focus_owner focus_owner, bool hide_caret,
+ int x, int y, int height, const struct rect *clip)
+{
+ union content_msg_data msg_data;
+ int x_off = 0;
+ int y_off = 0;
+ bool textarea_lost_focus = html->focus_type == HTML_FOCUS_TEXTAREA &&
+ focus_type != HTML_FOCUS_TEXTAREA;
+
+ assert(html != NULL);
+
+ switch (focus_type) {
+ case HTML_FOCUS_SELF:
+ assert(focus_owner.self == true);
+ if (html->focus_type == HTML_FOCUS_SELF)
+ /* Don't need to tell anyone anything */
+ return;
+ break;
+
+ case HTML_FOCUS_CONTENT:
+ box_coords(focus_owner.content, &x_off, &y_off);
+ break;
+
+ case HTML_FOCUS_TEXTAREA:
+ box_coords(focus_owner.textarea, &x_off, &y_off);
+ break;
+ }
+
+ html->focus_type = focus_type;
+ html->focus_owner = focus_owner;
+
+ if (textarea_lost_focus) {
+ msg_data.caret.type = CONTENT_CARET_REMOVE;
+ } else if (focus_type != HTML_FOCUS_SELF && hide_caret) {
+ msg_data.caret.type = CONTENT_CARET_HIDE;
+ } else {
+ msg_data.caret.type = CONTENT_CARET_SET_POS;
+ msg_data.caret.pos.x = x + x_off;
+ msg_data.caret.pos.y = y + y_off;
+ msg_data.caret.pos.height = height;
+ msg_data.caret.pos.clip = clip;
+ }
+
+ /* Inform of the content's drag status change */
+ content_broadcast((struct content *)html, CONTENT_MSG_CARET, msg_data);
+}
+
+/* Documented in html_internal.h */
+void html_set_selection(html_content *html, html_selection_type selection_type,
+ union html_selection_owner selection_owner, bool read_only)
+{
+ union content_msg_data msg_data;
+ struct box *box;
+ bool changed = false;
+ bool same_type = html->selection_type == selection_type;
+
+ assert(html != NULL);
+
+ if ((selection_type == HTML_SELECTION_NONE &&
+ html->selection_type != HTML_SELECTION_NONE) ||
+ (selection_type != HTML_SELECTION_NONE &&
+ html->selection_type == HTML_SELECTION_NONE))
+ /* Existance of selection has changed, and we'll need to
+ * inform our owner */
+ changed = true;
+
+ /* Clear any existing selection */
+ if (html->selection_type != HTML_SELECTION_NONE) {
+ switch (html->selection_type) {
+ case HTML_SELECTION_SELF:
+ if (same_type)
+ break;
+ selection_clear(&html->sel, true);
+ break;
+ case HTML_SELECTION_TEXTAREA:
+ if (same_type && html->selection_owner.textarea ==
+ selection_owner.textarea)
+ break;
+ box = html->selection_owner.textarea;
+ textarea_clear_selection(box->gadget->data.text.ta);
+ break;
+ case HTML_SELECTION_CONTENT:
+ if (same_type && html->selection_owner.content ==
+ selection_owner.content)
+ break;
+ box = html->selection_owner.content;
+ content_clear_selection(box->object);
+ break;
+ default:
+ break;
+ }
+ }
+
+ html->selection_type = selection_type;
+ html->selection_owner = selection_owner;
+
+ if (!changed)
+ /* Don't need to report lack of change to owner */
+ return;
+
+ /* Prepare msg */
+ switch (selection_type) {
+ case HTML_SELECTION_NONE:
+ assert(selection_owner.none == true);
+ msg_data.selection.selection = false;
+ break;
+ case HTML_SELECTION_SELF:
+ assert(selection_owner.none == false);
+ /* fall through */
+ case HTML_SELECTION_TEXTAREA:
+ case HTML_SELECTION_CONTENT:
+ msg_data.selection.selection = true;
+ break;
+ default:
+ break;
+ }
+ msg_data.selection.read_only = read_only;
+
+ /* Inform of the content's selection status change */
+ content_broadcast((struct content *)html, CONTENT_MSG_SELECTION,
+ msg_data);
+}
diff --git a/render/html_internal.h b/render/html_internal.h
index 3e562bc39..80b126b25 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -43,6 +43,29 @@ union html_drag_owner {
struct box *textarea;
}; /**< For drags we don't own */
+typedef enum {
+ HTML_SELECTION_NONE, /** No selection */
+ HTML_SELECTION_TEXTAREA, /** Selection in one of our textareas */
+ HTML_SELECTION_SELF, /** Selection in this html content */
+ HTML_SELECTION_CONTENT /** Selection in child content */
+} html_selection_type;
+union html_selection_owner {
+ bool none;
+ struct box *textarea;
+ struct box *content;
+}; /**< For getting at selections in this content or things in this content */
+
+typedef enum {
+ HTML_FOCUS_SELF, /** Focus is our own */
+ HTML_FOCUS_CONTENT, /** Focus belongs to child content */
+ HTML_FOCUS_TEXTAREA /** Focus belongs to textarea */
+} html_focus_type;
+union html_focus_owner {
+ bool self;
+ struct box *textarea;
+ struct box *content;
+}; /**< For directing input */
+
/** Data specific to CONTENT_HTML. */
typedef struct html_content {
struct content base;
@@ -114,18 +137,28 @@ typedef struct html_content {
* object within a page. */
struct html_content *page;
- /* Current drag type */
+ /** Current drag type */
html_drag_type drag_type;
/** Widget capturing all mouse events */
union html_drag_owner drag_owner;
+ /** Current selection state */
+ html_selection_type selection_type;
+ /** Current selection owner */
+ union html_selection_owner selection_owner;
+
+ /** Current input focus target type */
+ html_focus_type focus_type;
+ /** Current input focus target */
+ union html_focus_owner focus_owner;
+
+ /** HTML content's own text selection object */
+ struct selection sel;
+
/** Open core-handled form SELECT menu,
* or NULL if none currently open. */
struct form_control *visible_select_menu;
- /** Selection state */
- struct selection sel;
-
/** Context for free text search, or NULL if none */
struct search_context *search;
@@ -152,6 +185,34 @@ 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);
+/**
+ * Set our selection status, and inform whatever owns the content
+ *
+ * \param html HTML content
+ * \param selection_type Type of selection
+ * \param selection_owner What owns the selection
+ * \param read_only True iff selection is read only
+ */
+void html_set_selection(html_content *html, html_selection_type selection_type,
+ union html_selection_owner selection_owner, bool read_only);
+
+/**
+ * Set our input focus, and inform whatever owns the content
+ *
+ * \param html HTML content
+ * \param focus_type Type of input focus
+ * \param focus_owner What owns the focus
+ * \param hide_caret True iff caret to be hidden
+ * \param x Carret x-coord rel to owner
+ * \param y Carret y-coord rel to owner
+ * \param height Carret height
+ * \param clip Carret clip rect
+ */
+void html_set_focus(html_content *html, html_focus_type focus_type,
+ union html_focus_owner focus_owner, bool hide_caret,
+ int x, int y, int height, const struct rect *clip);
+
+
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);
@@ -179,6 +240,7 @@ 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);
+bool html_keypress(struct content *c, uint32_t key);
void html_overflow_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
diff --git a/render/textplain.c b/render/textplain.c
index 6cf334fe2..b9d0b81e5 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -40,6 +40,7 @@
#include "desktop/plotters.h"
#include "desktop/search.h"
#include "desktop/selection.h"
+#include "desktop/textinput.h"
#include "render/font.h"
#include "render/search.h"
#include "render/textplain.h"
@@ -107,6 +108,7 @@ static void textplain_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
static void textplain_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
+static bool textplain_keypress(struct content *c, uint32_t key);
static void textplain_reformat(struct content *c, int width, int height);
static void textplain_destroy(struct content *c);
static bool textplain_redraw(struct content *c, struct content_redraw_data *data,
@@ -114,7 +116,7 @@ static bool textplain_redraw(struct content *c, struct content_redraw_data *data
static void textplain_open(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params);
void textplain_close(struct content *c);
-struct selection *textplain_get_selection(struct content *c);
+char *textplain_get_selection(struct content *c);
struct search_context *textplain_get_search(struct content *c);
static nserror textplain_clone(const struct content *old,
struct content **newc);
@@ -139,6 +141,7 @@ static const content_handler textplain_content_handler = {
.destroy = textplain_destroy,
.mouse_track = textplain_mouse_track,
.mouse_action = textplain_mouse_action,
+ .keypress = textplain_keypress,
.redraw = textplain_redraw,
.open = textplain_open,
.close = textplain_close,
@@ -716,6 +719,46 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw,
/**
+ * Handle keypresses.
+ *
+ * \param c content of type CONTENT_TEXTPLAIN
+ * \param key The UCS4 character codepoint
+ * \return true if key handled, false otherwise
+ */
+
+bool textplain_keypress(struct content *c, uint32_t key)
+{
+ textplain_content *text = (textplain_content *) c;
+ struct selection *sel = &text->sel;
+
+ switch (key) {
+ case KEY_COPY_SELECTION:
+ selection_copy_to_clipboard(sel);
+ return true;
+
+ case KEY_CLEAR_SELECTION:
+ selection_clear(sel, true);
+ return true;
+
+ case KEY_SELECT_ALL:
+ selection_select_all(sel);
+ return true;
+
+ case KEY_ESCAPE:
+ if (selection_defined(sel)) {
+ selection_clear(sel, true);
+ return true;
+ }
+
+ /* if there's no selection, leave Escape for the caller */
+ return false;
+ }
+
+ return false;
+}
+
+
+/**
* Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
*
* \param c content of type CONTENT_TEXTPLAIN
@@ -893,11 +936,11 @@ void textplain_close(struct content *c)
* Return an textplain content's selection context
*/
-struct selection *textplain_get_selection(struct content *c)
+char *textplain_get_selection(struct content *c)
{
textplain_content *text = (textplain_content *) c;
- return &text->sel;
+ return selection_get_copy(&text->sel);
}