summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'desktop')
-rw-r--r--desktop/browser.c126
-rw-r--r--desktop/browser.h48
-rw-r--r--desktop/browser_private.h20
-rw-r--r--desktop/frames.c2
-rw-r--r--desktop/selection.c128
-rw-r--r--desktop/textarea.c183
-rw-r--r--desktop/textarea.h43
-rw-r--r--desktop/textinput.c80
8 files changed, 277 insertions, 353 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index ca72c41a2..fa0e6d121 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -428,42 +428,69 @@ struct browser_window * browser_window_get_root(struct browser_window *bw)
}
/* exported interface, documented in browser.h */
-bool browser_window_has_selection(struct browser_window *bw)
+browser_editor_flags browser_window_get_editor_flags(struct browser_window *bw)
{
+ browser_editor_flags ed_flags = BW_EDITOR_NONE;
assert(bw->window);
+ assert(bw->parent == NULL);
- if (bw->cur_sel != NULL && selection_defined(bw->cur_sel)) {
- return true;
- } else {
- return false;
+ if (bw->selection.bw != NULL) {
+ ed_flags |= BW_EDITOR_CAN_COPY;
+
+ if (!bw->selection.read_only)
+ ed_flags |= BW_EDITOR_CAN_CUT;
}
+
+ if (bw->can_edit)
+ ed_flags |= BW_EDITOR_CAN_PASTE;
+
+ return ed_flags;
}
/* exported interface, documented in browser.h */
-void browser_window_set_selection(struct browser_window *bw,
- struct selection *s)
+char * browser_window_get_selection(struct browser_window *bw)
{
assert(bw->window);
+ assert(bw->parent == NULL);
- if (bw->cur_sel != s && bw->cur_sel != NULL) {
- /* Clear any existing selection */
- selection_clear(bw->cur_sel, true);
- }
+ if (bw->selection.bw == NULL ||
+ bw->selection.bw->current_content == NULL)
+ return NULL;
- /* Replace current selection pointer */
- if (s == NULL && bw->current_content != NULL) {
- bw->cur_sel = content_get_selection(bw->current_content);
- } else {
- bw->cur_sel = s;
- }
+ return content_get_selection(bw->selection.bw->current_content);
}
-/* exported interface, documented in browser.h */
-struct selection *browser_window_get_selection(struct browser_window *bw)
+/**
+ * Set or remove a selection.
+ *
+ * \param bw browser window with selection
+ * \param selection true if bw has a selection, false if removing selection
+ * \param read_only true iff selection is read only (e.g. can't cut it)
+ */
+static void browser_window_set_selection(struct browser_window *bw,
+ bool selection, bool read_only)
{
- assert(bw->window);
+ struct browser_window *top;
+
+ assert(bw != NULL);
+
+ top = browser_window_get_root(bw);
+
+ assert(top != NULL);
- return bw->cur_sel;
+ if (bw != top->selection.bw && top->selection.bw != NULL &&
+ top->selection.bw->current_content != NULL) {
+ /* clear old selection */
+ content_clear_selection(top->selection.bw->current_content);
+ }
+
+ if (selection) {
+ top->selection.bw = bw;
+ } else {
+ top->selection.bw = NULL;
+ }
+
+ top->selection.read_only = read_only;
}
/* exported interface, documented in browser.h */
@@ -739,7 +766,6 @@ void browser_window_initialise_common(struct browser_window *bw,
bw->history = history_clone(clone->history);
/* window characteristics */
- bw->cur_sel = NULL;
bw->cur_search = NULL;
bw->refresh_interval = -1;
@@ -919,7 +945,7 @@ nserror browser_window_navigate(struct browser_window *bw,
}
browser_window_stop(bw);
- browser_window_remove_caret(bw);
+ browser_window_remove_caret(bw, false);
browser_window_destroy_children(bw);
LOG(("Loading '%s'", nsurl_access(url)));
@@ -1159,7 +1185,7 @@ browser_window_callback_errorcode(hlcache_handle *c,
bw->loading_content = NULL;
} else if (c == bw->current_content) {
bw->current_content = NULL;
- browser_window_remove_caret(bw);
+ browser_window_remove_caret(bw, false);
}
hlcache_handle_release(c);
@@ -1230,7 +1256,7 @@ nserror browser_window_callback(hlcache_handle *c,
browser_window_get_dimensions(bw, &width, &height, true);
content_reformat(c, false, width, height);
- browser_window_remove_caret(bw);
+ browser_window_remove_caret(bw, false);
if (bw->window)
gui_window_new_content(bw->window);
@@ -1260,11 +1286,6 @@ nserror browser_window_callback(hlcache_handle *c,
}
}
- if (bw->window != NULL) {
- browser_window_set_selection(bw,
- content_get_selection(c));
- }
-
/* frames */
if (content_get_type(c) == CONTENT_HTML &&
html_get_frameset(c) != NULL)
@@ -1315,7 +1336,7 @@ nserror browser_window_callback(hlcache_handle *c,
bw->loading_content = NULL;
else if (c == bw->current_content) {
bw->current_content = NULL;
- browser_window_remove_caret(bw);
+ browser_window_remove_caret(bw, false);
}
hlcache_handle_release(c);
@@ -1355,8 +1376,7 @@ nserror browser_window_callback(hlcache_handle *c,
browser_window_recalculate_iframes(bw);
}
- if (bw->move_callback)
- bw->move_callback(bw, bw->caret_p1, bw->caret_p2);
+ /* TODO: get caret pos redraw */
if (!(event->data.background)) {
/* Reformatted content should be redrawn */
@@ -1515,6 +1535,29 @@ nserror browser_window_callback(hlcache_handle *c,
}
break;
+ case CONTENT_MSG_CARET:
+ switch (event->data.caret.type) {
+ case CONTENT_CARET_REMOVE:
+ browser_window_remove_caret(bw, false);
+ break;
+ case CONTENT_CARET_HIDE:
+ browser_window_remove_caret(bw, true);
+ break;
+ case CONTENT_CARET_SET_POS:
+ browser_window_place_caret(bw,
+ event->data.caret.pos.x,
+ event->data.caret.pos.y,
+ event->data.caret.pos.height);
+ break;
+ }
+ break;
+
+ case CONTENT_MSG_SELECTION:
+ browser_window_set_selection(bw,
+ event->data.selection.selection,
+ event->data.selection.read_only);
+ break;
+
default:
assert(0);
}
@@ -2083,10 +2126,8 @@ void browser_window_destroy_internal(struct browser_window *bw)
if (top->focus == bw)
top->focus = top;
- if (bw->current_content != NULL &&
- top->cur_sel == content_get_selection(
- bw->current_content)) {
- browser_window_set_selection(top, NULL);
+ if (top->selection.bw == bw) {
+ browser_window_set_selection(top, false, false);
}
}
@@ -2734,7 +2775,18 @@ void browser_window_mouse_click(struct browser_window *bw,
switch (content_get_type(c)) {
case CONTENT_HTML:
case CONTENT_TEXTPLAIN:
+ {
+ /* Give bw focus */
+ struct browser_window *root_bw = browser_window_get_root(bw);
+ if (bw != root_bw->focus) {
+ browser_window_remove_caret(bw, false);
+ browser_window_set_selection(bw, false, true);
+ root_bw->focus = bw;
+ }
+
+ /* Pass mouse action to content */
content_mouse_action(c, bw, mouse, x, y);
+ }
break;
default:
if (mouse & BROWSER_MOUSE_MOD_2) {
diff --git a/desktop/browser.h b/desktop/browser.h
index cad8bf706..39f2253bf 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -40,14 +40,6 @@ struct history;
struct selection;
struct fetch_multipart_data;
-typedef bool (*browser_caret_callback)(struct browser_window *bw, uint32_t key,
- void *p1, void *p2);
-typedef void (*browser_move_callback)(struct browser_window *bw,
- void *p1, void *p2);
-typedef bool (*browser_paste_callback)(struct browser_window *bw,
- const char *utf8, unsigned utf8_len, bool last,
- void *p1, void *p2);
-
typedef enum {
DRAGGING_NONE,
@@ -60,6 +52,13 @@ typedef enum {
DRAGGING_OTHER
} browser_drag_type;
+typedef enum {
+ BW_EDITOR_NONE = 0, /**< No selection, no editing */
+ BW_EDITOR_CAN_COPY = (1 << 0), /**< Have selection */
+ BW_EDITOR_CAN_CUT = (1 << 1), /**< Selection not read-only */
+ BW_EDITOR_CAN_PASTE = (1 << 2) /**< Can paste, input */
+} browser_editor_flags;
+
extern bool browser_reformat_pending;
/** flags to browser window go */
@@ -206,15 +205,9 @@ bool browser_window_stop_available(struct browser_window *bw);
/* In desktop/textinput.c */
void browser_window_place_caret(struct browser_window *bw,
- int x, int y, int height,
- browser_caret_callback caret_cb,
- browser_paste_callback paste_cb,
- browser_move_callback move_cb,
- void *p1, void *p2);
-void browser_window_remove_caret(struct browser_window *bw);
+ int x, int y, int height);
+void browser_window_remove_caret(struct browser_window *bw, bool only_hide);
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);
/**
@@ -327,29 +320,22 @@ browser_drag_type browser_window_get_drag_type(struct browser_window *bw);
struct browser_window * browser_window_get_root(struct browser_window *bw);
/**
- * Check whether browser window contains a selection
- *
- * \param bw The browser window
- * \return true if browser window contains a selection
- */
-bool browser_window_has_selection(struct browser_window *bw);
-
-/**
- * Set pointer to current selection. Clears any existing selection.
+ * Check whether browser window can accept a cut/copy/paste, or has a selection
+ * that could be saved.
*
* \param bw The browser window
- * \param s The new selection
+ * \return flags indicating editor flags
*/
-void browser_window_set_selection(struct browser_window *bw,
- struct selection *s);
+browser_editor_flags browser_window_get_editor_flags(struct browser_window *bw);
/**
- * Get the current selection context from a root browser window
+ * Get the current selection from a root browser window, ownership passed to
+ * caller, who must free() it.
*
* \param bw The browser window
- * \return the selection context, or NULL
+ * \return the selected text string, or NULL
*/
-struct selection *browser_window_get_selection(struct browser_window *bw);
+char * browser_window_get_selection(struct browser_window *bw);
/**
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index 91372acc3..4c14b1700 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -52,18 +52,6 @@ struct browser_window {
/** Window history structure. */
struct history *history;
- /** Handler for keyboard input, or 0. */
- browser_caret_callback caret_callback;
- /** Handler for pasting text, or 0. */
- browser_paste_callback paste_callback;
- /** Handler for repositioning caret, or 0. */
- browser_move_callback move_callback;
-
- /** User parameters for caret_callback, paste_callback, and
- * move_callback */
- void *caret_p1;
- void *caret_p2;
-
/** Platform specific window data. */
struct gui_window *window;
@@ -158,8 +146,12 @@ struct browser_window {
/** Last time a link was followed in this window */
unsigned int last_action;
- /** Current selection, or NULL if none */
- struct selection *cur_sel;
+ /** Current selection */
+ struct {
+ struct browser_window *bw;
+ bool read_only;
+ } selection;
+ bool can_edit;
/** Current context for free text search, or NULL if none */
struct search_context *cur_search;
diff --git a/desktop/frames.c b/desktop/frames.c
index 27085ef3d..dcc66df9d 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -219,7 +219,6 @@ void browser_window_create_iframes(struct browser_window *bw,
window->no_resize = true;
window->margin_width = cur->margin_width;
window->margin_height = cur->margin_height;
- window->cur_sel = bw->cur_sel;
window->scale = bw->scale;
if (cur->name) {
window->name = strdup(cur->name);
@@ -338,7 +337,6 @@ void browser_window_create_frameset(struct browser_window *bw,
warn_user("NoMemory", 0);
}
- window->cur_sel = bw->cur_sel;
window->scale = bw->scale;
/* linking */
diff --git a/desktop/selection.c b/desktop/selection.c
index fa82ad027..536df5c84 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -77,9 +77,6 @@ static bool redraw_handler(const char *text, size_t length, struct box *box,
size_t whitespace_length);
static void selection_redraw(struct selection *s, unsigned start_idx,
unsigned end_idx);
-static bool save_handler(const char *text, size_t length, struct box *box,
- void *handle, const char *whitespace_text,
- size_t whitespace_length);
static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset);
static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
@@ -285,10 +282,6 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
(mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2));
int pos = -1; /* 0 = inside selection, 1 = after it */
struct browser_window *top = selection_get_browser_window(s);
-
- if (top == NULL)
- return false; /* not our problem */
-
top = browser_window_get_root(top);
if (selection_defined(s)) {
@@ -309,14 +302,12 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
}
else if (!modkeys) {
if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) {
- /* Clear the selection if mouse is pressed outside the selection,
- * Otherwise clear on release (to allow for drags) */
- browser_window_set_selection(top, s);
+ /* Clear the selection if mouse is pressed outside the
+ * selection, Otherwise clear on release (to allow for drags) */
selection_clear(s, true);
} else if (mouse & BROWSER_MOUSE_DRAG_1) {
/* start new selection drag */
- browser_window_set_selection(top, s);
selection_clear(s, true);
@@ -333,8 +324,6 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
if (!selection_defined(s))
return false; /* ignore Adjust drags */
- browser_window_set_selection(top, s);
-
if (pos >= 0) {
selection_set_end(s, idx);
@@ -907,7 +896,6 @@ void selection_clear(struct selection *s, bool redraw)
{
int old_start, old_end;
bool was_defined;
- struct browser_window *top = selection_get_browser_window(s);
assert(s);
was_defined = selection_defined(s);
@@ -918,13 +906,6 @@ void selection_clear(struct selection *s, bool redraw)
s->start_idx = 0;
s->end_idx = 0;
- if (!top)
- return;
-
- top = browser_window_get_root(top);
-
- gui_clear_selection(top->window);
-
if (redraw && was_defined)
selection_redraw(s, old_start, old_end);
}
@@ -1110,111 +1091,6 @@ bool selection_highlighted(const struct selection *s,
/**
- * Selection traversal handler for saving the text to a file.
- *
- * \param text pointer to text being added, or NULL for newline
- * \param length length of text to be appended (bytes)
- * \param box pointer to text box (or NULL for textplain content)
- * \param handle our save_state workspace pointer
- * \param whitespace_text whitespace to place before text for formatting
- * may be NULL
- * \param whitespace_length length of whitespace_text
- * \return true iff the file writing succeeded and traversal should continue.
- */
-
-bool save_handler(const char *text, size_t length, struct box *box,
- void *handle, const char *whitespace_text,
- size_t whitespace_length)
-{
- struct save_text_state *sv = handle;
- size_t new_length;
- int space = 0;
-
- assert(sv);
-
- if (box && (box->space > 0))
- space = 1;
-
- if (whitespace_text)
- length += whitespace_length;
-
- new_length = sv->length + whitespace_length + length + space;
- if (new_length >= sv->alloc) {
- size_t new_alloc = sv->alloc + (sv->alloc / 4);
- char *new_block;
-
- if (new_alloc < new_length) new_alloc = new_length;
-
- new_block = realloc(sv->block, new_alloc);
- if (!new_block) return false;
-
- sv->block = new_block;
- sv->alloc = new_alloc;
- }
- if (whitespace_text) {
- memcpy(sv->block + sv->length, whitespace_text,
- whitespace_length);
- }
- memcpy(sv->block + sv->length + whitespace_length, text, length);
- sv->length += length;
-
- if (space == 1)
- sv->block[sv->length++] = ' ';
-
- return true;
-}
-
-
-/**
- * Save the given selection to a file.
- *
- * \param s selection object
- * \param path pathname to be used
- * \return true iff the save succeeded
- */
-
-bool selection_save_text(struct selection *s, const char *path)
-{
- struct save_text_state sv = { NULL, 0, 0 };
- utf8_convert_ret ret;
- char *result;
- FILE *out;
-
- if (!selection_traverse(s, save_handler, &sv)) {
- free(sv.block);
- return false;
- }
-
- if (!sv.block)
- return false;
-
- ret = utf8_to_local_encoding(sv.block, sv.length, &result);
- free(sv.block);
-
- if (ret != UTF8_CONVERT_OK) {
- LOG(("failed to convert to local encoding, return %d", ret));
- return false;
- }
-
- out = fopen(path, "w");
- if (out) {
- int res = fputs(result, out);
- if (res < 0) {
- LOG(("Warning: writing data failed"));
- }
-
- res = fputs("\n", out);
- fclose(out);
- free(result);
- return (res != EOF);
- }
- free(result);
-
- return false;
-}
-
-
-/**
* Adjust the selection to reflect a change in the selected text,
* eg. editing in a text area/input field.
*
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 455e9a4ca..2da2c206b 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -180,6 +180,7 @@ static bool textarea_select(struct textarea *ta, int c_start, int c_end,
bool force_redraw)
{
int swap;
+ bool pre_existing_selection = (ta->sel_start != -1);
struct textarea_msg msg;
/* Ensure start is the beginning of the selection */
@@ -205,6 +206,24 @@ static bool textarea_select(struct textarea *ta, int c_start, int c_end,
ta->callback(ta->data, &msg);
+ if (!pre_existing_selection && ta->sel_start != -1) {
+ /* Didn't have a selection before, but do now */
+ msg.type = TEXTAREA_MSG_SELECTION_REPORT;
+
+ msg.data.selection.have_selection = true;
+ msg.data.selection.read_only = (ta->flags & TEXTAREA_READONLY);
+
+ ta->callback(ta->data, &msg);
+
+ if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
+ /* Caret hidden, and client is responsible */
+ msg.type = TEXTAREA_MSG_CARET_UPDATE;
+ msg.data.caret.type = TEXTAREA_CARET_HIDE;
+
+ ta->callback(ta->data, &msg);
+ }
+ }
+
return true;
}
@@ -438,11 +457,12 @@ static void textarea_scrollbar_callback(void *client_data,
if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
/* Tell client where caret should be placed */
msg.ta = ta;
- msg.type = TEXTAREA_MSG_MOVED_CARET;
- msg.data.caret.hidden = false;
- msg.data.caret.x = ta->caret_x - ta->scroll_x;
- msg.data.caret.y = ta->caret_y - ta->scroll_y;
- msg.data.caret.height = ta->line_height;
+ msg.type = TEXTAREA_MSG_CARET_UPDATE;
+ msg.data.caret.type = TEXTAREA_CARET_SET_POS;
+ msg.data.caret.pos.x = ta->caret_x - ta->scroll_x;
+ msg.data.caret.pos.y = ta->caret_y - ta->scroll_y;
+ msg.data.caret.pos.height = ta->line_height;
+ msg.data.caret.pos.clip = NULL;
ta->callback(ta->data, &msg);
}
@@ -497,7 +517,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
int avail_width;
int h_extent; /* horizontal extent */
int v_extent; /* vertical extent */
- bool restart;
+ bool restart = false;
if (ta->lines == NULL) {
ta->lines =
@@ -781,10 +801,10 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
line = y / ta->line_height;
- if (line < 0)
- line = 0;
if (ta->line_count - 1 < line)
line = ta->line_count - 1;
+ if (line < 0)
+ line = 0;
/* Get byte position */
nsfont.font_position_in_string(&ta->fstyle,
@@ -798,9 +818,7 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
* after it. Otherwise, the caret will be placed at the start of the
* following line, which is undesirable.
*/
- if (ta->flags & TEXTAREA_MULTILINE &&
- ta->show->data[ta->lines[line].b_start +
- ta->lines[line].b_length] > 0 &&
+ if (ta->flags & TEXTAREA_MULTILINE && ta->lines[line].b_length > 1 &&
bpos == (unsigned)ta->lines[line].b_length &&
ta->show->data[ta->lines[line].b_start +
ta->lines[line].b_length - 1] == ' ')
@@ -838,9 +856,9 @@ static bool textarea_set_caret_xy(struct textarea *ta, int x, int y)
/**
- * Insert text into the text area
+ * Insert text into the textarea
*
- * \param ta Text area
+ * \param ta Textarea widget
* \param c_index 0-based character index to insert at
* \param text UTF-8 text to insert
* \param b_len Byte length of UTF-8 text
@@ -908,9 +926,9 @@ static inline void textarea_char_to_byte_offset(struct textarea_utf8 *text,
/**
- * Replace text in a text area
+ * Replace text in a textarea
*
- * \param ta Text area
+ * \param ta Textarea widget
* \param start Start character index of replaced section (inclusive)
* \param end End character index of replaced section (exclusive)
* \param rep Replacement UTF-8 text to insert
@@ -1421,11 +1439,12 @@ bool textarea_set_caret(struct textarea *ta, int caret)
if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
/* Tell client where caret should be placed */
msg.ta = ta;
- msg.type = TEXTAREA_MSG_MOVED_CARET;
- msg.data.caret.hidden = false;
- msg.data.caret.x = x - ta->scroll_x;
- msg.data.caret.y = y - ta->scroll_y;
- msg.data.caret.height = ta->line_height;
+ msg.type = TEXTAREA_MSG_CARET_UPDATE;
+ msg.data.caret.type = TEXTAREA_CARET_SET_POS;
+ msg.data.caret.pos.x = x - ta->scroll_x;
+ msg.data.caret.pos.y = y - ta->scroll_y;
+ msg.data.caret.pos.height = ta->line_height;
+ msg.data.caret.pos.clip = NULL;
ta->callback(ta->data, &msg);
}
@@ -1433,8 +1452,8 @@ bool textarea_set_caret(struct textarea *ta, int caret)
} else if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
/* Caret hidden, and client is responsible: tell client */
msg.ta = ta;
- msg.type = TEXTAREA_MSG_MOVED_CARET;
- msg.data.caret.hidden = true;
+ msg.type = TEXTAREA_MSG_CARET_UPDATE;
+ msg.data.caret.type = TEXTAREA_CARET_HIDE;
ta->callback(ta->data, &msg);
}
@@ -1778,8 +1797,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start + 1;
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
} else {
if (!textarea_replace_text(ta,
caret, caret,
@@ -1792,11 +1810,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
} else switch (key) {
case KEY_SELECT_ALL:
caret = ta->text.utf8_len;
-
- ta->sel_start = 0;
- ta->sel_end = ta->text.utf8_len;
- redraw = true;
- break;
+ textarea_select(ta, 0, ta->text.utf8_len, true);
+ return true;
case KEY_COPY_SELECTION:
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
@@ -1816,15 +1831,15 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else if (caret > 0) {
if (!textarea_replace_text(ta,
caret - 1,
caret, "", 0, false))
return false;
caret--;
+ redraw = true;
}
- redraw = true;
break;
case KEY_CR:
case KEY_NL:
@@ -1838,15 +1853,15 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start + 1;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else {
if (!textarea_replace_text(ta,
caret, caret,
"\n", 1, false))
return false;
caret++;
+ redraw = true;
}
- redraw = true;
break;
case KEY_DELETE_LINE:
if (readonly)
@@ -1856,7 +1871,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else {
if (ta->lines[line].b_length != 0) {
/* Delete line */
@@ -1877,8 +1892,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
false))
return false;
}
+ redraw = true;
}
- redraw = true;
break;
case KEY_PASTE:
{
@@ -1903,7 +1918,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start + clipboard_chars;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else {
if (!textarea_replace_text(ta,
caret, caret,
@@ -1911,8 +1926,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
false))
return false;
caret += clipboard_chars;
+ redraw = true;
}
- redraw = true;
free(clipboard);
}
@@ -1927,8 +1942,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start;
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_ESCAPE:
@@ -1941,8 +1955,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
if (caret > 0)
caret--;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_RIGHT:
@@ -1951,8 +1964,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
if (caret < ta->text.utf8_len)
caret++;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_PAGE_UP:
@@ -1970,8 +1982,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
if (readonly)
break;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
if (!(ta->flags & TEXTAREA_MULTILINE))
break;
@@ -2012,16 +2023,14 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
/* -1 because one line is added in KEY_DOWN */
line = ta->caret_pos.line + (ta->vis_height +
ta->line_height - 1) /
- ta->line_height
- - 1;
+ ta->line_height - 1;
}
/* fall through */
case KEY_DOWN:
if (readonly)
break;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
if (!(ta->flags & TEXTAREA_MULTILINE))
break;
@@ -2065,8 +2074,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
caret = ta->sel_start;
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
} else {
if (caret < ta->text.utf8_len) {
if (!textarea_replace_text(ta,
@@ -2082,8 +2090,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
break;
caret -= ta->caret_pos.char_off;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_LINE_END:
@@ -2099,8 +2106,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
- 1] == ' ')
caret--;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_TEXT_START:
@@ -2108,8 +2114,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
break;
caret = 0;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_TEXT_END:
@@ -2117,8 +2122,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
break;
caret = ta->text.utf8_len;
if (ta->sel_start != -1) {
- ta->sel_start = ta->sel_end = -1;
- redraw = true;
+ textarea_clear_selection(ta);
}
break;
case KEY_WORD_LEFT:
@@ -2132,7 +2136,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else {
b_off = ta->lines[line].b_start;
b_len = ta->lines[line].b_length;
@@ -2142,8 +2146,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
if (!textarea_replace_text(ta, caret,
caret + l_len, "", 0, false))
return false;
+ redraw = true;
}
- redraw = true;
break;
case KEY_DELETE_LINE_START:
if (readonly)
@@ -2153,15 +2157,15 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
- ta->sel_start = ta->sel_end = -1;
+ textarea_clear_selection(ta);
} else {
if (!textarea_replace_text(ta,
caret - ta->caret_pos.char_off,
caret, "", 0, false))
return false;
caret -= ta->caret_pos.char_off;
+ redraw = true;
}
- redraw = true;
break;
default:
return false;
@@ -2346,6 +2350,7 @@ bool textarea_clear_selection(struct textarea *ta)
/* No selection to clear */
return false;
+ /* Clear selection and redraw */
ta->sel_start = ta->sel_end = -1;
msg.ta = ta;
@@ -2357,11 +2362,63 @@ bool textarea_clear_selection(struct textarea *ta)
ta->callback(ta->data, &msg);
+ /* No more selection */
+ msg.type = TEXTAREA_MSG_SELECTION_REPORT;
+
+ msg.data.selection.have_selection = false;
+ msg.data.selection.read_only = (ta->flags & TEXTAREA_READONLY);
+
+ ta->callback(ta->data, &msg);
+
+ if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
+ /* Tell client where caret should be placed */
+ msg.ta = ta;
+ msg.type = TEXTAREA_MSG_CARET_UPDATE;
+ msg.data.caret.type = TEXTAREA_CARET_SET_POS;
+ msg.data.caret.pos.x = ta->caret_x - ta->scroll_x;
+ msg.data.caret.pos.y = ta->caret_y - ta->scroll_y;
+ msg.data.caret.pos.height = ta->line_height;
+ msg.data.caret.pos.clip = NULL;
+
+ ta->callback(ta->data, &msg);
+ }
+
return true;
}
/* exported interface, documented in textarea.h */
+char *textarea_get_selection(struct textarea *ta)
+{
+ char *ret;
+ size_t b_start, b_end, b_len;
+
+ if (ta->sel_start == -1)
+ /* No selection get */
+ return NULL;
+
+ textarea_char_to_byte_offset(ta->show, ta->sel_start, ta->sel_end,
+ &b_start, &b_end);
+
+ b_len = b_end - b_start;
+
+ if (b_len == 0)
+ /* No selection get */
+ return NULL;
+
+ ret = malloc(b_len + 1); /* Add space for '\0' */
+ if (ret == NULL)
+ /* Can't get selection; no memory */
+ return NULL;
+
+ memcpy(ret, ta->show->data + b_start, b_len);
+ ret[b_len] = '\0';
+
+ return ret;
+}
+
+
+/* exported interface, documented in textarea.h */
void textarea_get_dimensions(struct textarea *ta, int *width, int *height)
{
if (width != NULL)
diff --git a/desktop/textarea.h b/desktop/textarea.h
index 3fedeee35..befd6aa99 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -45,28 +45,39 @@ typedef enum {
TEXTAREA_DRAG_NONE,
TEXTAREA_DRAG_SCROLLBAR,
TEXTAREA_DRAG_SELECTION
-} textarea_drag_type;
+} textarea_drag_type; /**< Textarea drag status */
typedef enum {
TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */
+ TEXTAREA_MSG_SELECTION_REPORT, /**< Textarea text selection presence */
TEXTAREA_MSG_REDRAW_REQUEST, /**< Textarea redraw request */
- TEXTAREA_MSG_MOVED_CARET /**< Textarea caret moved */
+ TEXTAREA_MSG_CARET_UPDATE /**< Textarea caret */
} textarea_msg_type;
struct textarea_msg {
- struct textarea *ta;
+ struct textarea *ta; /**< The textarea widget */
- textarea_msg_type type;
+ textarea_msg_type type; /**< Indicates message data type */
union {
- textarea_drag_type drag;
- struct rect redraw;
+ textarea_drag_type drag; /**< With _DRAG_REPORT */
struct {
- bool hidden;
- int x;
- int y;
- int height;
- } caret;
- } data;
+ bool have_selection; /**< Selection exists */
+ bool read_only; /**< Selection can't be cut */
+ } selection; /**< With _SELECTION_REPORT */
+ struct rect redraw; /**< With _REDRAW_REQUEST */
+ struct {
+ enum {
+ TEXTAREA_CARET_SET_POS, /**< Set coord/height */
+ TEXTAREA_CARET_HIDE /**< Hide */
+ } type;
+ struct {
+ int x; /**< Carret x-coord */
+ int y; /**< Carret y-coord */
+ int height; /**< Carret height */
+ struct rect *clip; /**< Carret clip rect */
+ } pos; /**< With _CARET_SET_POS */
+ } caret; /**< With _CARET_UPDATE */
+ } data; /**< Depends on msg type */
};
typedef struct textarea_setup {
@@ -206,6 +217,14 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
bool textarea_clear_selection(struct textarea *ta);
/**
+ * Get selected text, ownership passed to caller, which needs to free() it.
+ *
+ * \param ta Textarea widget
+ * \return Selected text, or NULL if none.
+ */
+char *textarea_get_selection(struct textarea *ta);
+
+/**
* Gets the dimensions of a textarea
*
* \param ta textarea widget
diff --git a/desktop/textinput.c b/desktop/textinput.c
index 660708932..6ffa02c86 100644
--- a/desktop/textinput.c
+++ b/desktop/textinput.c
@@ -63,11 +63,7 @@
* \param p2 Callback private data pointer, passed to callback function
*/
void browser_window_place_caret(struct browser_window *bw,
- int x, int y, int height,
- browser_caret_callback caret_cb,
- browser_paste_callback paste_cb,
- browser_move_callback move_cb,
- void *p1, void *p2)
+ int x, int y, int height)
{
struct browser_window *root_bw;
int pos_x = 0;
@@ -81,14 +77,10 @@ void browser_window_place_caret(struct browser_window *bw,
y = y * bw->scale + pos_y;
gui_window_place_caret(root_bw->window, x, y, height * bw->scale);
- bw->caret_callback = caret_cb;
- bw->paste_callback = paste_cb;
- bw->move_callback = move_cb;
- bw->caret_p1 = p1;
- bw->caret_p2 = p2;
/* Set focus browser window */
root_bw->focus = bw;
+ root_bw->can_edit = true;
}
@@ -97,20 +89,19 @@ void browser_window_place_caret(struct browser_window *bw,
*
* \param bw The browser window from which to remove caret
*/
-void browser_window_remove_caret(struct browser_window *bw)
+void browser_window_remove_caret(struct browser_window *bw, bool only_hide)
{
struct browser_window *root_bw;
root_bw = browser_window_get_root(bw);
+ if (only_hide)
+ root_bw->can_edit = true;
+ else
+ root_bw->can_edit = false;
+
if (root_bw && root_bw->window)
gui_window_remove_caret(root_bw->window);
-
- bw->caret_callback = NULL;
- bw->paste_callback = NULL;
- bw->move_callback = NULL;
- bw->caret_p1 = NULL;
- bw->caret_p2 = NULL;
}
@@ -127,59 +118,12 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
assert(bw->window != NULL);
- if (focus->caret_callback) {
- /* Pass keypress onto anything that has claimed input focus */
- return focus->caret_callback(focus, key,
- focus->caret_p1, focus->caret_p2);
- }
-
- /* TODO: pass these to content to deal with */
- switch (key) {
- case KEY_COPY_SELECTION:
- selection_copy_to_clipboard(bw->cur_sel);
- return true;
-
- case KEY_CLEAR_SELECTION:
- selection_clear(bw->cur_sel, true);
- return true;
-
- case KEY_SELECT_ALL:
- selection_select_all(bw->cur_sel);
- return true;
-
- case KEY_ESCAPE:
- if (bw->cur_sel && selection_defined(bw->cur_sel)) {
- selection_clear(bw->cur_sel, true);
- return true;
- }
- /* if there's no selection,
- * leave Escape for the caller */
- return false;
- }
-
- return false;
-}
-
-
-/**
- * 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
- *
- * TODO: Remove this function.
- */
+ if (focus == NULL)
+ focus = bw;
-bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
- unsigned utf8_len, bool last)
-{
- if (!bw->focus || !bw->focus->paste_callback)
+ if (focus->current_content == NULL)
return false;
- return bw->focus->paste_callback(bw->focus, utf8, utf8_len, last,
- bw->focus->caret_p1, bw->focus->caret_p2);
+ return content_keypress(focus->current_content, key);
}