From 31c659a2ea8bf239569c8436e3b718786879df47 Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Wed, 20 Apr 2005 12:24:41 +0000 Subject: [project @ 2005-04-20 12:24:41 by adrianl] text import from global clipboard, other apps & files and additional keys for editing text in textareas svn path=/import/netsurf/; revision=1673 --- desktop/browser.c | 9 + desktop/browser.h | 17 +- desktop/gui.h | 1 + desktop/textinput.c | 861 +++++++++++++++++++++++++++++++++++++++---------- desktop/textinput.h | 35 ++ gtk/gtk_window.c | 5 + render/box.c | 30 +- render/box.h | 1 + riscos/gui.h | 1 + riscos/save.c | 1 + riscos/textselection.c | 49 ++- riscos/window.c | 170 ++++++++-- 12 files changed, 975 insertions(+), 205 deletions(-) diff --git a/desktop/browser.c b/desktop/browser.c index 0a7775838..49d81dadd 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -97,6 +97,7 @@ void browser_window_create(const char *url, struct browser_window *clone, bw->sel = selection_create(bw); bw->throbbing = false; bw->caret_callback = NULL; + bw->paste_callback = NULL; bw->frag_id = NULL; bw->drag_type = DRAGGING_NONE; bw->scrolling_box = NULL; @@ -292,6 +293,7 @@ void browser_window_callback(content_msg msg, struct content *c, bw->current_content = c; bw->loading_content = NULL; bw->caret_callback = NULL; + bw->paste_callback = NULL; bw->scrolling_box = NULL; gui_window_new_content(bw->window); if (bw->frag_id) @@ -335,6 +337,7 @@ void browser_window_callback(content_msg msg, struct content *c, else if (c == bw->current_content) { bw->current_content = 0; bw->caret_callback = NULL; + bw->paste_callback = NULL; bw->scrolling_box = NULL; selection_init(bw->sel, NULL); } @@ -384,6 +387,7 @@ void browser_window_callback(content_msg msg, struct content *c, else if (c == bw->current_content) { bw->current_content = 0; bw->caret_callback = NULL; + bw->paste_callback = NULL; bw->scrolling_box = NULL; selection_init(bw->sel, NULL); } @@ -936,6 +940,11 @@ void browser_window_mouse_action_html(struct browser_window *bw, if (text_box && selection_click(bw->sel, text_box, mouse, x - box_x, y - box_y)) { + /* key presses must be directed at the main browser window, + paste text operations ignored */ + if (bw->caret_callback) bw->caret_callback = NULL; + if (bw->paste_callback) bw->paste_callback = NULL; + if (selection_dragging(bw->sel)) { bw->drag_type = DRAGGING_SELECTION; status = messages_get("Selecting"); diff --git a/desktop/browser.h b/desktop/browser.h index c8764da2c..f59974a39 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -25,6 +25,13 @@ struct form_successful_control; struct gui_window; struct history; struct selection; +struct browser_window; + + +typedef void (*browser_caret_callback)(struct browser_window *bw, + wchar_t key, void *p); +typedef bool (*browser_paste_callback)(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, void *p); /** Browser window data. */ struct browser_window { @@ -40,9 +47,11 @@ struct browser_window { struct selection *sel; /** Handler for keyboard input, or 0. */ - void (*caret_callback)(struct browser_window *bw, - wchar_t key, void *p); - /** User parameter for caret_callback. */ + browser_caret_callback caret_callback; + /** Handler for pasting text, or 0. */ + browser_paste_callback paste_callback; + + /** User parameter for caret_callback and paste_callback */ void *caret_p; /** Platform specific window data. */ @@ -125,6 +134,8 @@ void browser_window_mouse_drag_end(struct browser_window *bw, browser_mouse_state mouse, int x, int y); bool browser_window_key_press(struct browser_window *bw, wchar_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 content *c, struct box *box); diff --git a/desktop/gui.h b/desktop/gui.h index bcc39e21b..c56b2d504 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -85,6 +85,7 @@ void gui_drag_save_object(gui_save_type type, struct content *c, void gui_drag_save_selection(struct selection *s, struct gui_window *g); void gui_start_selection(struct gui_window *g); +void gui_paste_from_clipboard(struct gui_window *g, int x, int y); bool gui_copy_to_clipboard(struct selection *s); void gui_create_form_select_menu(struct browser_window *bw, diff --git a/desktop/textinput.c b/desktop/textinput.c index 1fdd49ebe..9fb9f5ccf 100644 --- a/desktop/textinput.c +++ b/desktop/textinput.c @@ -6,6 +6,7 @@ * Copyright 2004 James Bursa * Copyright 2004 Andrew Timmins * Copyright 2004 John Tytgat + * Copyright 2005 Adrian Lees */ /** \file @@ -23,7 +24,7 @@ #include "netsurf/render/font.h" #include "netsurf/render/form.h" #include "netsurf/render/layout.h" -#define NDEBUG +//#define NDEBUG #include "netsurf/utils/log.h" #include "netsurf/utils/talloc.h" #include "netsurf/utils/utf8.h" @@ -35,9 +36,27 @@ static void browser_window_input_callback(struct browser_window *bw, wchar_t key, void *p); static void browser_window_place_caret(struct browser_window *bw, int x, int y, int height, - void (*callback)(struct browser_window *bw, - wchar_t key, void *p), + browser_caret_callback caret_cb, + browser_paste_callback paste_cb, void *p); +static bool browser_window_textarea_paste_text(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, void *handle); +static bool browser_window_input_paste_text(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, void *handle); +static void input_update_display(struct browser_window *bw, struct box *input, + unsigned form_offset, unsigned box_offset, bool to_textarea, + bool redraw); +static bool textbox_insert(struct browser_window *bw, struct box *text_box, + unsigned char_offset, const char *utf8, unsigned utf8_len); +static bool textbox_delete(struct browser_window *bw, struct box *text_box, + unsigned char_offset, unsigned utf8_len); +static struct box *textarea_insert_break(struct browser_window *bw, + struct box *text_box, size_t char_offset); +static bool delete_handler(struct box *b, int offset, size_t length, + void *handle); +static void textarea_reflow(struct browser_window *bw, struct box *textarea, + struct box *inline_container); + /** * Handle clicks in a text area by placing the caret. @@ -142,7 +161,9 @@ void browser_window_textarea_click(struct browser_window *bw, pixel_offset, box_y + inline_container->y + text_box->y, text_box->height, - browser_window_textarea_callback, textarea); + browser_window_textarea_callback, + browser_window_textarea_paste_text, + textarea); if (new_scroll_y != textarea->scroll_y) { textarea->scroll_y = new_scroll_y; @@ -165,16 +186,13 @@ void browser_window_textarea_callback(struct browser_window *bw, struct box *inline_container = textarea->gadget->caret_inline_container; struct box *text_box = textarea->gadget->caret_text_box; - struct box *new_br, *new_text, *t; - struct box *prev; + struct box *new_text; size_t char_offset = textarea->gadget->caret_box_offset; int pixel_offset = textarea->gadget->caret_pixel_offset; int new_scroll_y; int box_x, box_y; char utf8[6]; - unsigned int utf8_len, i; - char *text; - int width = 0, height = 0; + unsigned int utf8_len; bool reflow = false; /* box_dump(textarea, 0); */ @@ -189,65 +207,39 @@ void browser_window_textarea_callback(struct browser_window *bw, /* normal character insertion */ utf8_len = utf8_from_ucs4(key, utf8); - text = talloc_realloc(bw->current_content, text_box->text, - char, text_box->length + 8); - if (!text) { - warn_user("NoMemory", 0); + if (!textbox_insert(bw, text_box, char_offset, utf8, utf8_len)) return; - } - text_box->text = text; - memmove(text_box->text + char_offset + utf8_len, - text_box->text + char_offset, - text_box->length - char_offset); - for (i = 0; i != utf8_len; i++) - text_box->text[char_offset + i] = utf8[i]; - text_box->length += utf8_len; - text_box->text[text_box->length] = 0; - text_box->width = UNKNOWN_WIDTH; - char_offset += utf8_len; + char_offset += utf8_len; reflow = true; } else switch (key) { - case 8: - case 127: /* delete to left */ + case KEY_DELETE_LEFT: if (char_offset == 0) { /* at the start of a text box */ - if (!text_box->prev) - /* at very beginning of text area: ignore */ - return; + struct box *prev; - if (text_box->prev->type == BOX_BR) { + while (text_box->prev && text_box->prev->type == BOX_BR) { /* previous box is BR: remove it */ - t = text_box->prev; - t->prev->next = t->next; - t->next->prev = t->prev; - box_free(t); + box_unlink_and_free(text_box->prev); } + if (!text_box->prev) + /* at very beginning of text area: ignore */ + return; + /* delete space by merging with previous text box */ prev = text_box->prev; + assert(prev->type == BOX_INLINE); assert(prev->text); - text = talloc_realloc(bw->current_content, - prev->text, char, - prev->length + text_box->length + 1); - if (!text) { - warn_user("NoMemory", 0); - return; - } - prev->text = text; - memcpy(prev->text + prev->length, text_box->text, - text_box->length); + char_offset = prev->length; /* caret at join */ - prev->length += text_box->length; - prev->text[prev->length] = 0; - prev->width = UNKNOWN_WIDTH; - prev->next = text_box->next; - if (prev->next) - prev->next->prev = prev; - else - prev->parent->last = prev; - box_free(text_box); + + if (!textbox_insert(bw, prev, prev->length, + text_box->text, text_box->length)) + return; + + box_unlink_and_free(text_box); /* place caret at join (see above) */ text_box = prev; @@ -257,45 +249,54 @@ void browser_window_textarea_callback(struct browser_window *bw, int prev_offset = char_offset; char_offset = utf8_prev(text_box->text, char_offset); - memmove(text_box->text + char_offset, - text_box->text + prev_offset, - text_box->length - prev_offset); - text_box->length -= (prev_offset - char_offset); - text_box->width = UNKNOWN_WIDTH; + textbox_delete(bw, text_box, char_offset, prev_offset - char_offset); } - reflow = true; break; - case 10: - case 13: /* paragraph break */ - text = talloc_array(bw->current_content, char, - text_box->length + 1); - if (!text) { - warn_user("NoMemory", 0); - return; - } + case KEY_DELETE_RIGHT: /* delete to right */ + if (char_offset >= text_box->length) { + /* at the end of a text box */ + struct box *next; - new_br = box_create(text_box->style, 0, text_box->title, 0, - bw->current_content); - new_text = talloc(bw->current_content, struct box); - if (!new_text) { - warn_user("NoMemory", 0); - return; - } + while (text_box->next && text_box->next->type == BOX_BR) { + /* next box is a BR: remove it */ + box_unlink_and_free(text_box->next); + } + + if (!text_box->next) + /* at very end of text area: ignore */ + return; + + /* delete space by merging with next text box */ + + next = text_box->next; + assert(next->type == BOX_INLINE); + assert(next->text); + + if (!textbox_insert(bw, text_box, text_box->length, + next->text, next->length)) + return; - new_br->type = BOX_BR; - box_insert_sibling(text_box, new_br); + box_unlink_and_free(next); + + /* leave caret at join */ + reflow = true; + } + else { + /* delete a character */ + int next_offset = utf8_next(text_box->text, text_box->length, + char_offset); + textbox_delete(bw, text_box, char_offset, + next_offset - char_offset); + } + reflow = true; + break; - memcpy(new_text, text_box, sizeof (struct box)); - new_text->clone = 1; - new_text->text = text; - memcpy(new_text->text, text_box->text + char_offset, - text_box->length - char_offset); - new_text->length = text_box->length - char_offset; - text_box->length = char_offset; - text_box->width = new_text->width = UNKNOWN_WIDTH; - box_insert_sibling(new_br, new_text); + case 10: + case 13: /* paragraph break */ + new_text = textarea_insert_break(bw, text_box, char_offset); + if (!new_text) return; /* place caret at start of new text box */ text_box = new_text; @@ -304,18 +305,52 @@ void browser_window_textarea_callback(struct browser_window *bw, reflow = true; break; + case 21: { /* Ctrl + U */ + struct box *next; + + /* run back to start of line */ + while (text_box->prev && text_box->prev->type == BOX_INLINE) + text_box = text_box->prev; + + /* run forwards to end */ + next = text_box->next; + while (next && next->type == BOX_INLINE) { + box_unlink_and_free(text_box); + text_box = next; + next = text_box->next; + } + + /* can we take out this last inline and and the following BR? */ + if (next && next->type == BOX_BR && next->next) { + box_unlink_and_free(text_box); + + /* place caret at start of next box */ + text_box = next->next; + box_unlink_and_free(next); + } + else + textbox_delete(bw, text_box, 0, text_box->length); + + char_offset = 0; + reflow = true; + } + break; + case 22: /* Ctrl + V */ -// gui_paste_from_clipboard(); + gui_paste_from_clipboard(bw->window, + box_x + inline_container->x + text_box->x + pixel_offset, + box_y + inline_container->y + text_box->y); break; case 24: /* Ctrl + X */ if (gui_copy_to_clipboard(bw->sel)) { - /** \todo block delete */ + selection_traverse(bw->sel, delete_handler, bw); + reflow = true; } break; - case 28: /* Right cursor -> */ - if ((unsigned int) char_offset != text_box->length) { + case KEY_RIGHT: + if ((unsigned int) char_offset < text_box->length) { char_offset = utf8_next(text_box->text, text_box->length, char_offset); } else { @@ -330,7 +365,7 @@ void browser_window_textarea_callback(struct browser_window *bw, } break; - case 29: /* Left cursor <- */ + case KEY_LEFT: if (char_offset != 0) { char_offset = utf8_prev(text_box->text, char_offset); } else { @@ -345,7 +380,7 @@ void browser_window_textarea_callback(struct browser_window *bw, } break; - case 30: /* Up cursor */ + case KEY_UP: browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1, textarea, box_x, box_y, @@ -353,7 +388,7 @@ void browser_window_textarea_callback(struct browser_window *bw, inline_container->y + text_box->y - 1); return; - case 31: /* Down cursor */ + case KEY_DOWN: browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1, textarea, box_x, box_y, @@ -362,6 +397,70 @@ void browser_window_textarea_callback(struct browser_window *bw, text_box->height + 1); return; + case KEY_LINE_START: + while (text_box->prev && text_box->prev->type == BOX_INLINE) + text_box = text_box->prev; + char_offset = 0; + break; + + case KEY_LINE_END: + while (text_box->next && text_box->next->type == BOX_INLINE) + text_box = text_box->next; + char_offset = text_box->length; + break; + + case KEY_TEXT_START: + assert(text_box->parent); + + /* place caret at start of first box */ + text_box = text_box->parent->children; + char_offset = 0; + break; + + case KEY_TEXT_END: + assert(text_box->parent); + + /* place caret at end of last box */ + text_box = text_box->parent->last; + char_offset = text_box->length; + break; + + case KEY_WORD_LEFT: +// while () { +// } + break; + + case KEY_WORD_RIGHT: +// while () { +// } + break; + + case KEY_PAGE_UP: +// while () { +// } + if (char_offset > text_box->length) + char_offset = text_box->length; + break; + + case KEY_PAGE_DOWN: + +// while () { +// } + if (char_offset > text_box->length) + char_offset = text_box->length; + break; + + case KEY_DELETE_LINE_START: + textbox_delete(bw, text_box, 0, char_offset); + reflow = true; + break; + + case KEY_DELETE_LINE_END: + textbox_delete(bw, text_box, char_offset, + text_box->length - char_offset); + reflow = true; + break; + default: return; } @@ -384,18 +483,8 @@ void browser_window_textarea_callback(struct browser_window *bw, } } */ - if (reflow) { - /* reflow textarea preserving width and height */ - width = textarea->width; - height = textarea->height; - if (!layout_inline_container(inline_container, width, - textarea, 0, 0, - bw->current_content)) - warn_user("NoMemory", 0); - textarea->width = width; - textarea->height = height; - layout_calculate_descendant_bboxes(textarea); - } + if (reflow) + textarea_reflow(bw, textarea, inline_container); if (text_box->length < char_offset) { /* the text box has been split and the caret is in the @@ -406,6 +495,14 @@ void browser_window_textarea_callback(struct browser_window *bw, assert(char_offset <= text_box->length); } + nsfont_width(text_box->style, text_box->text, + char_offset, &pixel_offset); + + textarea->gadget->caret_inline_container = inline_container; + textarea->gadget->caret_text_box = text_box; + textarea->gadget->caret_box_offset = char_offset; + textarea->gadget->caret_pixel_offset = pixel_offset; + /* scroll to place the caret in the centre of the visible region */ new_scroll_y = inline_container->y + text_box->y + text_box->height / 2 - @@ -416,19 +513,14 @@ void browser_window_textarea_callback(struct browser_window *bw, new_scroll_y = 0; box_y += textarea->scroll_y - new_scroll_y; - nsfont_width(text_box->style, text_box->text, - char_offset, &pixel_offset); - - textarea->gadget->caret_inline_container = inline_container; - textarea->gadget->caret_text_box = text_box; - textarea->gadget->caret_box_offset = char_offset; - textarea->gadget->caret_pixel_offset = pixel_offset; browser_window_place_caret(bw, box_x + inline_container->x + text_box->x + pixel_offset, box_y + inline_container->y + text_box->y, text_box->height, - browser_window_textarea_callback, textarea); + browser_window_textarea_callback, + browser_window_textarea_paste_text, + textarea); if (new_scroll_y != textarea->scroll_y || reflow) { textarea->scroll_y = new_scroll_y; @@ -508,7 +600,9 @@ void browser_window_input_click(struct browser_window* bw, text_box->x + pixel_offset, box_y + input->children->y + text_box->y, text_box->height, - browser_window_input_callback, input); + browser_window_input_callback, + browser_window_input_paste_text, + input); if (dx) browser_redraw_box(bw->current_content, input); @@ -529,7 +623,7 @@ void browser_window_input_callback(struct browser_window *bw, struct box *text_box = input->children->children; unsigned int box_offset = input->gadget->caret_box_offset; unsigned int form_offset = input->gadget->caret_form_offset; - int pixel_offset, dx; + int pixel_offset = input->gadget->caret_pixel_offset; int box_x, box_y; struct form* form = input->gadget->form; bool changed = false; @@ -575,20 +669,9 @@ void browser_window_input_callback(struct browser_window *bw, '*' : (key == ' ') ? 160 : key, utf8); - value = talloc_realloc(bw->current_content, text_box->text, - char, text_box->length + utf8_len + 1); - if (!value) { - warn_user("NoMemory", 0); + if (!textbox_insert(bw, text_box, box_offset, utf8, utf8_len)) return; - } - text_box->text = value; - memmove(text_box->text + box_offset + utf8_len, - text_box->text + box_offset, - text_box->length - box_offset); - memcpy(text_box->text + box_offset, utf8, utf8_len); - text_box->length += utf8_len; - text_box->text[text_box->length] = 0; box_offset += utf8_len; nsfont_width(text_box->style, text_box->text, @@ -596,8 +679,7 @@ void browser_window_input_callback(struct browser_window *bw, changed = true; } else switch (key) { - case 8: - case 127: { /* Delete to left */ + case KEY_DELETE_LEFT: { int prev_offset; if (box_offset == 0) @@ -620,11 +702,41 @@ void browser_window_input_callback(struct browser_window *bw, /* Go to the previous valid UTF-8 character */ box_offset = utf8_prev(text_box->text, box_offset); - memmove(text_box->text + box_offset, - text_box->text + prev_offset, - text_box->length - prev_offset); - text_box->length -= prev_offset - box_offset; - text_box->text[text_box->length] = 0; + textbox_delete(bw, text_box, box_offset, + prev_offset - box_offset); + + nsfont_width(text_box->style, text_box->text, + text_box->length, &text_box->width); + + changed = true; + } + break; + + case KEY_DELETE_RIGHT: { + unsigned next_offset; + + if (box_offset >= text_box->length) + return; + + /* Gadget */ + /* Go to the next valid UTF-8 character */ + next_offset = utf8_next(input->gadget->value, + input->gadget->length, + form_offset); + + memmove(input->gadget->value + form_offset, + input->gadget->value + next_offset, + input->gadget->length - next_offset); + input->gadget->length -= next_offset - form_offset; + input->gadget->value[input->gadget->length] = 0; + + /* Text box */ + /* Go to the next valid UTF-8 character */ + next_offset = utf8_next(text_box->text, text_box->length, + box_offset); + + textbox_delete(bw, text_box, box_offset, + next_offset - box_offset); nsfont_width(text_box->style, text_box->text, text_box->length, &text_box->width); @@ -647,7 +759,6 @@ void browser_window_input_callback(struct browser_window *bw, input = next_input->box; text_box = input->children->children; - box_coords(input, &box_x, &box_y); form_offset = box_offset = 0; to_textarea = next_input->type == GADGET_TEXTAREA; } @@ -673,7 +784,6 @@ void browser_window_input_callback(struct browser_window *bw, input = prev_input->box; text_box = input->children->children; - box_coords(input, &box_x, &box_y); form_offset = box_offset = 0; to_textarea = prev_input->type == GADGET_TEXTAREA; } @@ -693,10 +803,12 @@ void browser_window_input_callback(struct browser_window *bw, break; case 22: /* Ctrl + V */ -// gui_paste_from_clipboard(); + gui_paste_from_clipboard(bw->window, + box_x + input->children->x + text_box->x + pixel_offset, + box_y + input->children->y + text_box->y); break; - case 28: /* Right cursor -> */ + case KEY_RIGHT: /* Text box */ /* Go to the next valid UTF-8 character */ box_offset = utf8_next(text_box->text, text_box->length, @@ -707,7 +819,7 @@ void browser_window_input_callback(struct browser_window *bw, input->gadget->length, form_offset); break; - case 29: /* Left cursor -> */ + case KEY_LEFT: /* Text box */ /* Go to the previous valid UTF-8 character */ box_offset = utf8_prev(text_box->text, box_offset); @@ -716,11 +828,11 @@ void browser_window_input_callback(struct browser_window *bw, form_offset = utf8_prev(input->gadget->value, form_offset); break; - case 128: /* Ctrl + Left */ + case KEY_LINE_START: box_offset = form_offset = 0; break; - case 129: /* Ctrl + Right */ + case KEY_LINE_END: box_offset = text_box->length; form_offset = input->gadget->length; break; @@ -729,39 +841,10 @@ void browser_window_input_callback(struct browser_window *bw, return; } - nsfont_width(text_box->style, text_box->text, box_offset, - &pixel_offset); - dx = text_box->x; - text_box->x = 0; - if (input->width < text_box->width && - input->width / 2 < pixel_offset) { - text_box->x = input->width / 2 - pixel_offset; - if (text_box->x < input->width - text_box->width) - text_box->x = input->width - text_box->width; - } - dx -= text_box->x; - input->gadget->caret_pixel_offset = pixel_offset; - - if (to_textarea) { - /* moving to textarea so need to set these up */ - input->gadget->caret_inline_container = input->children; - input->gadget->caret_text_box = text_box; - } - - input->gadget->caret_box_offset = box_offset; input->gadget->caret_form_offset = form_offset; - browser_window_place_caret(bw, - box_x + input->children->x + - text_box->x + pixel_offset, - box_y + input->children->y + text_box->y, - text_box->height, - /* use the appropriate callback */ - to_textarea ? browser_window_textarea_callback - : browser_window_input_callback, input); - - if (dx || changed) - browser_redraw_box(bw->current_content, input); + input_update_display(bw, input, form_offset, box_offset, + to_textarea, changed); } @@ -771,18 +854,20 @@ void browser_window_input_callback(struct browser_window *bw, * \param bw The browser window in which to place the caret * \param x X coordinate of the caret * \param y Y coordinate - * \param height Height of caret - * \param callback Callback function for keypresses + * \param height Height of caret + * \param caret_cb Callback function for keypresses + * \param paste_cb Callback function for pasting text * \param p Callback private data pointer, passed to callback function */ void browser_window_place_caret(struct browser_window *bw, int x, int y, int height, - void (*callback)(struct browser_window *bw, - wchar_t key, void *p), + browser_caret_callback caret_cb, + browser_paste_callback paste_cb, void *p) { gui_window_place_caret(bw->window, x, y, height); - bw->caret_callback = callback; + bw->caret_callback = caret_cb; + bw->paste_callback = paste_cb; bw->caret_p = p; } @@ -828,7 +913,8 @@ bool browser_window_key_press(struct browser_window *bw, wchar_t key) selection_clear(bw->sel, true); return true; } - break; + /* if there's no selection, leave Escape for the caller */ + return false; } /* pass on to the appropriate field */ @@ -837,3 +923,424 @@ bool browser_window_key_press(struct browser_window *bw, wchar_t key) bw->caret_callback(bw, key, bw->caret_p); return true; } + + +/** + * Paste a block of text into a browser window at the caret position. + * + * \param bw browser window + * \param utf8 pointer to block of text + * \param utf8_len length (bytes) of text block + * \param last true iff this is the last chunk (update screen too) + * \return true iff successful + */ + +bool browser_window_paste_text(struct browser_window *bw, const char *utf8, + unsigned utf8_len, bool last) +{ + if (!bw->paste_callback) + return false; + return bw->paste_callback(bw, utf8, utf8_len, last, bw->caret_p); +} + + +/** + * Paste a block of text into a textarea at the + * current caret position. + * + * \param bw browser window + * \param utf8 pointer to block of text + * \param utf8_len length (bytes) of text block + * \param last true iff this is the last chunk (update screen too) + * \param handle pointer to textarea + * \return true iff successful + */ + +bool browser_window_textarea_paste_text(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, void *handle) +{ + struct box *textarea = handle; + struct box *inline_container = + textarea->gadget->caret_inline_container; + struct box *text_box = textarea->gadget->caret_text_box; + size_t char_offset = textarea->gadget->caret_box_offset; + int pixel_offset = textarea->gadget->caret_pixel_offset; + const char *ep = utf8 + utf8_len; + const char *p = utf8; + bool success = true; + bool update = last; + + while (p < ep) { + struct box *new_text; + unsigned utf8_len; + + while (p < ep) { + if (*p == '\n' || *p == '\r') break; + p++; + } + + utf8_len = p - utf8; + if (!textbox_insert(bw, text_box, char_offset, utf8, utf8_len)) + return false; + + char_offset += utf8_len; + + new_text = textarea_insert_break(bw, text_box, char_offset); + if (!new_text) { + /* we still need to update the screen */ + update = true; + success = false; + break; + } + + /* place caret at start of new text box */ + text_box = new_text; + char_offset = 0; + + /* handle CR/LF and LF/CR terminations */ + if ((*p == '\n' && p[1] == '\r') || (*p == '\r' && p[1] == '\n')) + p++; + utf8 = ++p; + } + + if (update) { + int box_x, box_y; + + /* reflow textarea preserving width and height */ + textarea_reflow(bw, textarea, inline_container); + + nsfont_width(text_box->style, text_box->text, + char_offset, &pixel_offset); + + box_x -= textarea->scroll_x; + box_y -= textarea->scroll_y; + + box_coords(textarea, &box_x, &box_y); + + browser_window_place_caret(bw, + box_x + inline_container->x + text_box->x + + pixel_offset, + box_y + inline_container->y + text_box->y, + text_box->height, + browser_window_textarea_callback, + browser_window_textarea_paste_text, + textarea); + + textarea->gadget->caret_pixel_offset = pixel_offset; + + browser_redraw_box(bw->current_content, textarea); + } + +// textarea->gadget->caret_inline_container = inline_container; + textarea->gadget->caret_text_box = text_box; + textarea->gadget->caret_box_offset = char_offset; + + return success; +} + + +/** + * Paste a block of text into an input field at the caret position. + * + * \param bw browser window + * \param utf8 pointer to block of text + * \param utf8_len length (bytes) of text block + * \param last true iff this is the last chunk (update screen too) + * \param p pointer to input box + * \return true iff successful + */ + +bool browser_window_input_paste_text(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, void *handle) +{ + struct box *input = handle; + struct box *text_box = input->children->children; + unsigned int box_offset = input->gadget->caret_box_offset; + unsigned int form_offset = input->gadget->caret_form_offset; + unsigned int nchars = utf8_length(input->gadget->value); + const char *ep = utf8 + utf8_len; + const char *p = utf8; + bool success = true; + bool update = last; + + /* keep adding chars until we've run out or would exceed + the maximum length of the field (in which we silently + ignore all others) + */ + while (p < ep && nchars < input->gadget->maxlength) { + char buf[80 + 6]; + int nbytes = 0; + unsigned utf8_len; + char *value; + + /* how many more chars can we insert in one go? */ + while (p < ep && nbytes < 80 && + nchars < input->gadget->maxlength && + *p != '\n' && *p != '\r') { + unsigned len = utf8_next(p, ep - p, 0); + + if (input->gadget->type == GADGET_PASSWORD) + buf[nbytes++] = '*'; + else if (*p == ' ') + nbytes += utf8_from_ucs4(160, &buf[nbytes]); + else { + memcpy(&buf[nbytes], p, len); + nbytes += len; + } + + p += len; + nchars++; + } + + utf8_len = p - utf8; + + value = realloc(input->gadget->value, + input->gadget->length + utf8_len + 1); + if (!value) { + /* we still need to update the screen */ + warn_user("NoMemory", 0); + update = true; + success = false; + break; + } + input->gadget->value = value; + + memmove(input->gadget->value + form_offset + utf8_len, + input->gadget->value + form_offset, + input->gadget->length - form_offset); + memcpy(input->gadget->value + form_offset, utf8, utf8_len); + input->gadget->length += utf8_len; + input->gadget->value[input->gadget->length] = 0; + form_offset += utf8_len; + + if (!textbox_insert(bw, text_box, box_offset, buf, nbytes)) { + /* we still need to update the screen */ + update = true; + success = false; + break; + } + box_offset += nbytes; + + /* handle CR/LF and LF/CR terminations */ + if (*p == '\n') { + p++; + if (*p == '\r') p++; + } + else if (*p == '\r') { + p++; + if (*p == '\n') p++; + } + utf8 = p; + } + + if (update) { + + nsfont_width(text_box->style, text_box->text, text_box->length, + &text_box->width); + + input_update_display(bw, input, form_offset, box_offset, false, true); + } + + return success; +} + + +/** + * Update display to reflect modified input field + * + * \param bw browser window + * \param input input field + * \param form_offset + * \param box_offset offset of caret within text box + * \param to_textarea caret is to be moved to a textarea + * \param redraw force redraw even if field hasn't scrolled + */ + +void input_update_display(struct browser_window *bw, struct box *input, + unsigned form_offset, unsigned box_offset, bool to_textarea, + bool redraw) +{ + struct box *text_box = input->children->children; + unsigned pixel_offset; + int box_x, box_y; + int dx; + + box_coords(input, &box_x, &box_y); + + nsfont_width(text_box->style, text_box->text, box_offset, + &pixel_offset); + dx = text_box->x; + text_box->x = 0; + if (input->width < text_box->width && + input->width / 2 < pixel_offset) { + text_box->x = input->width / 2 - pixel_offset; + if (text_box->x < input->width - text_box->width) + text_box->x = input->width - text_box->width; + } + dx -= text_box->x; + input->gadget->caret_pixel_offset = pixel_offset; + + if (to_textarea) { + /* moving to textarea so need to set these up */ + input->gadget->caret_inline_container = input->children; + input->gadget->caret_text_box = text_box; + } + + input->gadget->caret_box_offset = box_offset; + input->gadget->caret_form_offset = form_offset; + + browser_window_place_caret(bw, + box_x + input->children->x + + text_box->x + pixel_offset, + box_y + input->children->y + text_box->y, + text_box->height, + /* use the appropriate callback */ + to_textarea ? browser_window_textarea_callback + : browser_window_input_callback, + to_textarea ? browser_window_textarea_paste_text + : browser_window_input_paste_text, + input); + + if (dx || redraw) + browser_redraw_box(bw->current_content, input); +} + + +/** + * Insert a number of chars into a text box + * + * \param bw browser window + * \param text_box text box + * \param char_offset offsets (bytes) at which to insert text + * \param utf8 UTF-8 text to insert + * \param utf8_len length (bytes) of UTF-8 text to insert + * \return true iff successful + */ + +bool textbox_insert(struct browser_window *bw, struct box *text_box, + unsigned char_offset, const char *utf8, unsigned utf8_len) +{ + char *text = talloc_realloc(bw->current_content, text_box->text, + char, text_box->length + utf8_len + 1); + if (!text) { + warn_user("NoMemory", 0); + return false; + } + text_box->text = text; + memmove(text_box->text + char_offset + utf8_len, + text_box->text + char_offset, + text_box->length - char_offset); + memcpy(text_box->text + char_offset, utf8, utf8_len); + text_box->length += utf8_len; + + /* nothing should assume that the text is terminated, but just in case */ + text_box->text[text_box->length] = 0; + + text_box->width = UNKNOWN_WIDTH; + + return true; +} + + +/** + * Delete a number of chars from a text box + * + * \param bw browser window + * \param text_box text box + * \param char_offset offset within text box (bytes) of first char to delete + * \param utf8_len length (bytes) of chars to be deleted + */ + +bool textbox_delete(struct browser_window *bw, struct box *text_box, + unsigned char_offset, unsigned utf8_len) +{ + unsigned prev_offset = char_offset + utf8_len; + if (prev_offset <= text_box->length) { + memmove(text_box->text + char_offset, + text_box->text + prev_offset, + text_box->length - prev_offset); + text_box->length -= (prev_offset - char_offset); + + /* nothing should assume that the text is terminated, but just in case */ + text_box->text[text_box->length] = 0; + + text_box->width = UNKNOWN_WIDTH; + return true; + } + return false; +} + + +bool delete_handler(struct box *b, int offset, size_t length, void *handle) +{ + struct browser_window *bw = handle; + return textbox_delete(bw, b, offset, length); +} + + +/** + * Break a text box into two + * + * \param bw browser window + * \param text_box text box to be split + * \param char_offset offset (in bytes) at which text box is to be split + */ + +struct box *textarea_insert_break(struct browser_window *bw, struct box *text_box, + size_t char_offset) +{ + struct box *new_br, *new_text; + char *text = talloc_array(bw->current_content, char, + text_box->length + 1); + if (!text) { + warn_user("NoMemory", 0); + return NULL; + } + + new_br = box_create(text_box->style, 0, text_box->title, 0, + bw->current_content); + new_text = talloc(bw->current_content, struct box); + if (!new_text) { + warn_user("NoMemory", 0); + return NULL; + } + + new_br->type = BOX_BR; + box_insert_sibling(text_box, new_br); + + memcpy(new_text, text_box, sizeof (struct box)); + new_text->clone = 1; + new_text->text = text; + memcpy(new_text->text, text_box->text + char_offset, + text_box->length - char_offset); + new_text->length = text_box->length - char_offset; + text_box->length = char_offset; + text_box->width = new_text->width = UNKNOWN_WIDTH; + box_insert_sibling(new_br, new_text); + + return new_text; +} + + +/** + * Reflow textarea preserving width and height + * + * \param bw browser window + * \param textarea text area box + * \param inline_container container holding text box + */ + +void textarea_reflow(struct browser_window *bw, struct box *textarea, + struct box *inline_container) +{ + int width = textarea->width; + int height = textarea->height; + if (!layout_inline_container(inline_container, width, + textarea, 0, 0, + bw->current_content)) + warn_user("NoMemory", 0); + textarea->width = width; + textarea->height = height; + layout_calculate_descendant_bboxes(textarea); +} + diff --git a/desktop/textinput.h b/desktop/textinput.h index 155f526a0..c599ca0e1 100644 --- a/desktop/textinput.h +++ b/desktop/textinput.h @@ -12,16 +12,51 @@ * Textual input handling (interface) */ +#ifndef _NETSURF_DESKTOP_TEXTINPUT_H_ +#define _NETSURF_DESKTOP_TEXTINPUT_H_ + +#include + struct browser_window; struct box; + +enum input_key { + + KEY_DELETE_LEFT = 8, + + /* cursor movement keys */ + KEY_LEFT = 28, + KEY_RIGHT, + KEY_UP, + KEY_DOWN, + + KEY_DELETE_RIGHT = 127, + + KEY_LINE_START = 128, + KEY_LINE_END, + KEY_TEXT_START, + KEY_TEXT_END, + KEY_WORD_LEFT, + KEY_WORD_RIGHT, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_DELETE_LINE_END, + KEY_DELETE_LINE_START, +}; + + void browser_window_textarea_click(struct browser_window *bw, browser_mouse_state mouse, struct box *textarea, int box_x, int box_y, int x, int y); +//bool browser_window_textarea_paste(struct browser_window *bw, + void browser_window_input_click(struct browser_window* bw, struct box *input, int box_x, int box_y, int x, int y); void browser_window_remove_caret(struct browser_window *bw); + +#endif diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c index e215a002d..4f9f385d7 100644 --- a/gtk/gtk_window.c +++ b/gtk/gtk_window.c @@ -380,6 +380,11 @@ void gui_start_selection(struct gui_window *g) } +void gui_paste_from_clipboard(struct browser_window *bw, int x, int y) +{ +} + + bool gui_copy_to_clipboard(struct selection *s) { return false; diff --git a/render/box.c b/render/box.c index 7e0df2483..f00b8aa1d 100644 --- a/render/box.c +++ b/render/box.c @@ -133,7 +133,35 @@ void box_insert_sibling(struct box *box, struct box *new_box) /** - * Free the a box tree recursively. + * Unlink a box from the box tree and then free it recursively. + * + * \param box box to unlink and free recursively. + */ + +void box_unlink_and_free(struct box *box) +{ + struct box *parent = box->parent; + struct box *next = box->next; + struct box *prev = box->prev; + + if (parent) { + if (parent->children == box) + parent->children = next; + if (parent->last == box) + parent->last = next ? next : prev; + } + + if (prev) + prev->next = next; + if (next) + next->prev = prev; + + box_free(box); +} + + +/** + * Free a box tree recursively. * * \param box box to free recursively * diff --git a/render/box.h b/render/box.h index bcdf79005..60aba1ba5 100644 --- a/render/box.h +++ b/render/box.h @@ -234,6 +234,7 @@ struct box * box_create(struct css_style *style, char *id, void *context); void box_add_child(struct box *parent, struct box *child); void box_insert_sibling(struct box *box, struct box *new_box); +void box_unlink_and_free(struct box *box); void box_free(struct box *box); void box_free_box(struct box *box); void box_free_object_params(struct object_params *op); diff --git a/riscos/gui.h b/riscos/gui.h index 71eb73852..9293046bb 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -161,6 +161,7 @@ void ro_gui_scroll_request(wimp_scroll *scroll); //#define window_y_units(y, state) (y - (state->visible.y1 - state->yscroll)) int window_x_units(int x, wimp_window_state *state); int window_y_units(int y, wimp_window_state *state); +bool window_screen_pos(struct gui_window *g, int x, int y, os_coord *pos); bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message); void ro_gui_window_process_reformats(void); void ro_gui_window_default_options(struct browser_window *bw); diff --git a/riscos/save.c b/riscos/save.c index d4841bb56..9a4c11072 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -3,6 +3,7 @@ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license * Copyright 2004 James Bursa + * Copyright 2005 Adrian Lees */ /** \file diff --git a/riscos/textselection.c b/riscos/textselection.c index 67779bf6e..c6e4be57f 100644 --- a/riscos/textselection.c +++ b/riscos/textselection.c @@ -258,6 +258,53 @@ bool gui_copy_to_clipboard(struct selection *s) } +/** + * Request to paste the clipboard contents into a textarea/input field + * at a given position. Note that the actual operation may take place + * straight away (local clipboard) or in a number of chunks at some + * later time (clipboard owned by another app). + * + * \param g gui window + * \param x x ordinate at which to paste text + * \param y y ordinate at which to paste text + */ + +void gui_paste_from_clipboard(struct gui_window *g, int x, int y) +{ + if (owns_clipboard) { + if (clip_length > 0) + browser_window_paste_text(g->bw, clipboard, clip_length, true); + } + else { + wimp_full_message_data_request msg; + os_error *error; + os_coord pos; + + if (!window_screen_pos(g, x, y, &pos)) + return; + + msg.size = sizeof(msg); + msg.your_ref = 0; + msg.action = message_DATA_REQUEST; + msg.w = g->window; + msg.i = -1; + msg.pos.x = pos.x; + msg.pos.y = pos.y; + msg.flags = wimp_DATA_REQUEST_CLIPBOARD; + msg.file_types[0] = osfile_TYPE_TEXT; + msg.file_types[1] = ~0; + + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)&msg, + wimp_BROADCAST); + if (error) { + LOG(("xwimp_send_message: 0x%x : %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + } +} + + /** * Discard the current contents of the clipboard, if any, releasing the * memory it uses. @@ -306,8 +353,6 @@ void ro_gui_selection_claim_entity(wimp_full_message_claim_entity *claim) void ro_gui_selection_data_request(wimp_full_message_data_request *req) { - LOG(("%x owns %d size %d", req->flags, owns_clipboard, req->size)); - if (owns_clipboard && clip_length > 0 && (req->flags & wimp_DATA_REQUEST_CLIPBOARD)) { wimp_full_message_data_xfer message; diff --git a/riscos/window.c b/riscos/window.c index 9c04494a1..5bf5a1edd 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -20,6 +20,7 @@ #include #include "oslib/colourtrans.h" #include "oslib/osbyte.h" +#include "oslib/osfile.h" #include "oslib/osspriteop.h" #include "oslib/serviceinternational.h" #include "oslib/wimp.h" @@ -28,7 +29,9 @@ #include "netsurf/content/content.h" #include "netsurf/content/url_store.h" #include "netsurf/css/css.h" +#include "netsurf/desktop/browser.h" #include "netsurf/desktop/plotters.h" +#include "netsurf/desktop/textinput.h" #include "netsurf/render/box.h" #include "netsurf/render/form.h" #include "netsurf/riscos/buffer.h" @@ -48,6 +51,10 @@ #include "netsurf/utils/utils.h" #include "netsurf/utils/messages.h" +#ifndef wimp_KEY_END +#define wimp_KEY_END wimp_KEY_COPY +#endif + /** List of all browser windows. */ static struct gui_window *window_list = 0; @@ -62,6 +69,7 @@ static float scale_snap_to[] = {0.10, 0.125, 0.25, 0.333, 0.5, 0.75, static void ro_gui_window_clone_options(struct browser_window *new_bw, struct browser_window *old_bw); static browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons); +static bool ro_gui_window_import_text(struct gui_window *g, const char *filename); @@ -1616,14 +1624,29 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) /* We can't map onto 1->26 (reserved for ctrl+ That leaves 27->31 and 128->159 */ - if (c == 394) c = 9; /* Tab */ - else if (c == 410) c = 11; /* Shift+Tab */ - else if (c == 428) c = 128; /* Ctrl+Left */ - else if (c == 429) c = 129; /* Ctrl+Right*/ - else if (c == 396) c = 29; /* Left */ - else if (c == 397) c = 28; /* Right */ - else if (c == 398) c = 31; /* Down */ - else if (c == 399) c = 30; /* Up */ + switch (key) { + case wimp_KEY_TAB: c = 9; break; + case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; + + /* cursor movement keys */ + case wimp_KEY_CONTROL | wimp_KEY_LEFT: c = KEY_LINE_START; break; + case wimp_KEY_END: + case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break; + case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break; + case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break; + case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break; + case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break; + case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break; + case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break; + case wimp_KEY_LEFT: c = KEY_LEFT; break; + case wimp_KEY_RIGHT: c = KEY_RIGHT; break; + case wimp_KEY_UP: c = KEY_UP; break; + case wimp_KEY_DOWN: c = KEY_DOWN; break; + + /* editing */ + case wimp_KEY_CONTROL | wimp_KEY_END: c = 136; break; + } + if (c < 256) { if ((wchar_t)key > 256) /* do nothing */; @@ -1685,7 +1708,7 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) "%x (ignoring)", c)); return true; } - + /* Continuation of UTF8 character */ wc |= ((c & 0x3F) << (6 * --shift)); if (shift > 0) @@ -1992,6 +2015,35 @@ int window_y_units(int y, wimp_window_state *state) { } +/** + * Convert x,y window co-ordinates into screen co-ordinates. + * + * \param g gui window + * \param x x ordinate + * \param y y ordinate + * \param pos receives position in screen co-ordinatates + * \return true iff conversion successful + */ + +bool window_screen_pos(struct gui_window *g, int x, int y, os_coord *pos) +{ + wimp_window_state state; + os_error *error; + + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return false; + } + pos->x = state.visible.x0 + ((x * 2 * g->option.scale) - state.xscroll); + pos->y = state.visible.y1 + ((-y * 2 * g->option.scale) - state.yscroll); + return true; +} + + /** * Handle Message_DataLoad (file dragged in) for a window. * @@ -2008,6 +2060,7 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) int x, y; struct box *box; struct box *file_box = 0; + struct box *text_box = 0; struct browser_window *bw = g->bw; struct content *content; wimp_window_state state; @@ -2021,7 +2074,7 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) if (0x1000 <= message->data.data_xfer.file_type) return false; - /* Search for a file input at the drop point. */ + /* Search for a file input or text area at the drop point. */ state.w = message->data.data_xfer.w; error = xwimp_get_window_state(&state); if (error) { @@ -2043,23 +2096,49 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) box->style->visibility == CSS_VISIBILITY_HIDDEN) continue; - if (box->gadget && box->gadget->type == GADGET_FILE) - file_box = box; + if (box->gadget) { + switch (box->gadget->type) { + case GADGET_FILE: + file_box = box; + break; + + case GADGET_TEXTBOX: + case GADGET_TEXTAREA: + case GADGET_PASSWORD: + text_box = box; + break; + + default: /* appease compiler */ + break; + } + } } - if (!file_box) + if (!file_box && !text_box) return false; - /* Found: update form input. */ - free(file_box->gadget->value); - file_box->gadget->value = - strdup(message->data.data_xfer.file_name); + if (file_box) { - /* Redraw box. */ - box_coords(file_box, &x, &y); - gui_window_redraw(bw->window, x, y, - x + file_box->width, - y + file_box->height); + /* Found: update form input. */ + free(file_box->gadget->value); + file_box->gadget->value = + strdup(message->data.data_xfer.file_name); + + /* Redraw box. */ + box_coords(file_box, &x, &y); + gui_window_redraw(bw->window, x, y, + x + file_box->width, + y + file_box->height); + } + else { + + const char *filename = message->data.data_xfer.file_name; + + browser_window_mouse_click(g->bw, BROWSER_MOUSE_CLICK_1, x, y); + + if (!ro_gui_window_import_text(g, filename)) + return true; /* it was for us, it just didn't work! */ + } /* send DataLoadAck */ message->action = message_DATA_LOAD_ACK; @@ -2470,3 +2549,50 @@ void ro_gui_window_set_scale(struct gui_window *g, float scale) browser_window_update(g->bw, false); gui_reformat_pending = true; } + + +/** + * Import text file into textarea at caret position + * + * \param g gui window containing textarea + * \param filename pathname of file to be imported + * \return true iff successful + */ + +bool ro_gui_window_import_text(struct gui_window *g, const char *filename) +{ + fileswitch_object_type obj_type; + os_error *error; + char *buf; + int size; + + error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, + &size, NULL, NULL); + if (error) { + LOG(("xosfile_read_stamped: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return true; /* was for us, but it didn't work! */ + } + + buf = malloc(size); + if (!buf) { + warn_user("NoMemory", NULL); + return true; + } + + error = xosfile_load_stamped(filename, (byte*)buf, + NULL, NULL, NULL, NULL, NULL); + if (error) { + LOG(("xosfile_load_stamped: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("LoadError", error->errmess); + free(buf); + return true; + } + + browser_window_paste_text(g->bw, buf, size, true); + + free(buf); + return true; +} -- cgit v1.2.3