From dbfdafdf1820a95995c3b260e147c55125468874 Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Wed, 15 Feb 2006 23:09:55 +0000 Subject: [project @ 2006-02-15 23:09:53 by adrianl] Extend text selection, copying, saving and searching code to handle textplain contents; modified textplain code to accept other line terminators svn path=/import/netsurf/; revision=2081 --- riscos/dialog.c | 1 + riscos/download.c | 3 +- riscos/gui.c | 28 ++++- riscos/gui.h | 20 ---- riscos/message.c | 37 +++++++ riscos/message.h | 3 + riscos/save.c | 51 +++++++--- riscos/textselection.c | 271 +++++++++++++++++++++++++++++++++++++++++++++---- riscos/ucstables.c | 3 +- riscos/wimp.c | 29 ------ riscos/wimp.h | 1 - 11 files changed, 357 insertions(+), 90 deletions(-) (limited to 'riscos') diff --git a/riscos/dialog.c b/riscos/dialog.c index 0f6dcb043..e41dfb9b5 100644 --- a/riscos/dialog.c +++ b/riscos/dialog.c @@ -29,6 +29,7 @@ #include "netsurf/riscos/gui.h" #include "netsurf/riscos/menus.h" #include "netsurf/riscos/options.h" +#include "netsurf/riscos/save.h" #include "netsurf/riscos/theme.h" #include "netsurf/riscos/url_complete.h" #include "netsurf/riscos/wimp.h" diff --git a/riscos/download.c b/riscos/download.c index d377bb128..171b7ffcc 100644 --- a/riscos/download.c +++ b/riscos/download.c @@ -34,6 +34,7 @@ #include "netsurf/desktop/gui.h" #include "netsurf/riscos/dialog.h" #include "netsurf/riscos/options.h" +#include "netsurf/riscos/save.h" #include "netsurf/riscos/query.h" #include "netsurf/riscos/wimp.h" #include "netsurf/utils/log.h" @@ -1294,7 +1295,7 @@ bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit) struct gui_download_window *d = download_window_list; while (d) { - ro_gui_open_window_at_front(d->window); + ro_gui_dialog_open_top(d->window, NULL, 0, 0); d = d->next; } } diff --git a/riscos/gui.c b/riscos/gui.c index 840cc0364..5d58e8e36 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -64,7 +64,9 @@ #include "netsurf/riscos/print.h" #endif #include "netsurf/riscos/query.h" +#include "netsurf/riscos/save.h" #include "netsurf/riscos/save_complete.h" +#include "netsurf/riscos/textselection.h" #include "netsurf/riscos/theme.h" #include "netsurf/riscos/treeview.h" #ifdef WITH_URI @@ -166,7 +168,7 @@ static struct { } prev_sigs; /** Accepted wimp user messages. */ -static wimp_MESSAGE_LIST(38) task_messages = { { +static wimp_MESSAGE_LIST(40) task_messages = { { message_HELP_REQUEST, message_DATA_SAVE, message_DATA_SAVE_ACK, @@ -180,6 +182,8 @@ static wimp_MESSAGE_LIST(38) task_messages = { { message_MODE_CHANGE, message_CLAIM_ENTITY, message_DATA_REQUEST, + message_DRAGGING, + message_DRAG_CLAIM, #ifdef WITH_URI message_URI_PROCESS, message_URI_RETURN_RESULT, @@ -396,6 +400,10 @@ void gui_init(int argc, char** argv) ro_msg_prequit); ro_message_register_route(message_SAVE_DESKTOP, ro_msg_save_desktop); + ro_message_register_route(message_DRAGGING, + ro_gui_selection_dragging); + ro_message_register_route(message_DRAG_CLAIM, + ro_gui_selection_drag_claim); /* end of handler registration */ nsfont_init(); @@ -930,6 +938,7 @@ void gui_multitask(void) ro_gui_handle_event(event, &block); } + /** * Handle Null_Reason_Code events. */ @@ -963,6 +972,10 @@ void ro_gui_null_reason_code(void) ro_gui_window_mouse_at(gui_track_gui_window, &pointer); break; +// case GUI_DRAG_SAVE: +// ro_gui_selection_send_dragging(&pointer); +// break; + default: if (gui_track_wimp_w == history_window) ro_gui_history_mouse_at(&pointer); @@ -1078,7 +1091,13 @@ void ro_gui_close_window_request(wimp_close *close) if (ro_gui_shift_pressed()) return; ro_gui_url_complete_close(NULL, 0); + + /* search must be closed before the main window so that + the content still exists */ + ro_gui_dialog_close_persistent(close->w); browser_window_destroy(g->bw); + return; + } else if ((dw = ro_gui_download_window_lookup(close->w)) != NULL) { ro_gui_download_window_destroy(dw, false); } else { @@ -1106,8 +1125,9 @@ void ro_gui_pointer_leaving_window(wimp_leaving *leaving) switch (gui_current_drag_type) { case GUI_DRAG_SELECTION: case GUI_DRAG_SCROLL: + case GUI_DRAG_SAVE: /* ignore Pointer_Leaving_Window event that the Wimp mysteriously - issues when a Wimp_DragBox drag operations is started */ + issues when a Wimp_DragBox drag operation is started */ break; default: @@ -1745,6 +1765,9 @@ void ro_msg_datasave(wimp_message *message) { wimp_full_message_data_xfer *dataxfer = (wimp_full_message_data_xfer*)message; + /* remove ghost caret if drag-and-drop protocol was used */ +// ro_gui_selection_drag_reset(); + ro_msg_terminate_filename(dataxfer); switch (dataxfer->file_type) { @@ -1801,6 +1824,7 @@ void ro_msg_datasave_ack(wimp_message *message) case GUI_DRAG_SAVE: ro_gui_save_datasave_ack(message); + gui_current_drag_type = GUI_DRAG_NONE; break; default: diff --git a/riscos/gui.h b/riscos/gui.h index 0526650e4..629316ccb 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -119,14 +119,6 @@ bool ro_gui_download_window_keypress(struct gui_download_window *dw, wimp_key *k /* in mouseactions.c */ void ro_gui_mouse_action(struct gui_window *g); -/* in textselection.c */ -void ro_gui_selection_drag_end(struct gui_window *g, wimp_dragged *drag); -void ro_gui_selection_claim_entity(wimp_full_message_claim_entity *claim); -void ro_gui_selection_data_request(wimp_full_message_data_request *req); -bool ro_gui_save_clipboard(const char *path); -void ro_gui_selection_dragging(wimp_full_message_dragging *drag); -void ro_gui_selection_drag_claim(wimp_full_message_drag_claim *drag); - /* in 401login.c */ #ifdef WITH_AUTH void ro_gui_401login_init(void); @@ -180,18 +172,6 @@ void ro_gui_hotlist_prepare_entry_dialog(struct node *node); bool ro_gui_hotlist_dialog_apply(wimp_w w); int ro_gui_hotlist_help(int x, int y); -/* in save.c */ -wimp_w ro_gui_saveas_create(const char *template_name); -void ro_gui_saveas_quit(void); -void ro_gui_save_prepare(gui_save_type save_type, struct content *c); -void ro_gui_save_start_drag(wimp_pointer *pointer); -void ro_gui_drag_icon(int x, int y, const char *sprite); -void ro_gui_save_drag_end(wimp_dragged *drag); -void ro_gui_send_datasave(gui_save_type save_type, wimp_full_message_data_xfer *message, wimp_t to); -void ro_gui_save_datasave_ack(wimp_message *message); -bool ro_gui_save_ok(wimp_w w); -void ro_gui_convert_save_path(char *dp, size_t len, const char *p); - /* in filetype.c */ int ro_content_filetype(struct content *content); int ro_content_filetype_from_type(content_type type); diff --git a/riscos/message.c b/riscos/message.c index 20ad8f37f..40a465e61 100644 --- a/riscos/message.c +++ b/riscos/message.c @@ -67,6 +67,43 @@ bool ro_message_send_message(wimp_event_no event, wimp_message *message, } +/** + * Sends a message and registers a return route for a bounce. + * + * \param event the message event type + * \param message the message to register a route back for + * \param to_w the window to send the message to + * \param to_i the icon + * \param callback the code to call on a bounce + * \param to_t receives the task handle of the window's creator + * \return true on success, false otherwise + */ +bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *message, + wimp_w to_w, wimp_i to_i, void (*callback)(wimp_message *message), + wimp_t *to_t) { + os_error *error; + + assert(message); + + /* send a message */ + error = xwimp_send_message_to_window(event, message, to_w, to_i, to_t); + if (error) { + LOG(("xwimp_send_message_to_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return false; + } + + /* register the default bounce handler */ + if (callback) { + assert(event == wimp_USER_MESSAGE_RECORDED); + return ro_message_register_handler(message, message->action, + callback); + } + return true; +} + + /** * Registers a return route for a message. * diff --git a/riscos/message.h b/riscos/message.h index 3b05d3f03..1da372acb 100644 --- a/riscos/message.h +++ b/riscos/message.h @@ -17,6 +17,9 @@ bool ro_message_send_message(wimp_event_no event, wimp_message *message, wimp_t task, void (*callback)(wimp_message *message)); +bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *message, + wimp_w to_w, wimp_i to_i, void (*callback)(wimp_message *message), + wimp_t *to_t); bool ro_message_register_handler(wimp_message *message, unsigned int message_code, void (*callback)(wimp_message *message)); diff --git a/riscos/save.c b/riscos/save.c index e2a315a56..50335e948 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -31,8 +31,10 @@ #include "netsurf/riscos/gui.h" #include "netsurf/riscos/menus.h" #include "netsurf/riscos/options.h" +#include "netsurf/riscos/save.h" #include "netsurf/riscos/save_complete.h" #include "netsurf/riscos/save_draw.h" +#include "netsurf/riscos/textselection.h" #include "netsurf/riscos/thumbnail.h" #include "netsurf/riscos/wimp.h" #include "netsurf/riscos/wimp_event.h" @@ -49,6 +51,7 @@ static struct content *gui_save_content = NULL; static struct selection *gui_save_selection = NULL; static int gui_save_filetype; +static bool dragbox_active = false; /** there is a Wimp_DragBox or DragASprite call in progress */ static bool using_dragasprite = true; static bool saving_from_dialog = true; static osspriteop_area *saveas_area = NULL; @@ -365,6 +368,7 @@ void ro_gui_drag_icon(int x, int y, const char *sprite) if (!error) { using_dragasprite = true; + dragbox_active = true; return; } @@ -386,6 +390,8 @@ void ro_gui_drag_icon(int x, int y, const char *sprite) error->errnum, error->errmess)); warn_user("DragError", error->errmess); } + else + dragbox_active = true; } @@ -413,6 +419,31 @@ void ro_gui_convert_save_path(char *dp, size_t len, const char *p) } +void ro_gui_drag_box_cancel(void) +{ + if (dragbox_active) { + os_error *error; + if (using_dragasprite) { + error = xdragasprite_stop(); + if (error) { + LOG(("xdragasprite_stop: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + } + else { + error = xwimp_drag_box(NULL); + if (error) { + LOG(("xwimp_drag_box: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + } + dragbox_active = false; + } +} + + /** * Handle User_Drag_Box event for a drag from the save dialog or browser window. */ @@ -427,22 +458,8 @@ void ro_gui_save_drag_end(wimp_dragged *drag) char *local_name = NULL; utf8_convert_ret err; - if (using_dragasprite) { - error = xdragasprite_stop(); - if (error) { - LOG(("xdragasprite_stop: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - } - else { - error = xwimp_drag_box(NULL); - if (error) { - LOG(("xwimp_drag_box: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - } + if (dragbox_active) + ro_gui_drag_box_cancel(); error = xwimp_get_pointer_info(&pointer); if (error) { @@ -488,7 +505,9 @@ void ro_gui_save_drag_end(wimp_dragged *drag) ro_gui_convert_save_path(dp, ep - dp, name); +/* \todo - we're supposed to set this if drag-n-drop used */ message.your_ref = 0; + message.action = message_DATA_SAVE; message.data.data_xfer.w = pointer.w; message.data.data_xfer.i = pointer.i; diff --git a/riscos/textselection.c b/riscos/textselection.c index 5e2ddf750..603f645ea 100644 --- a/riscos/textselection.c +++ b/riscos/textselection.c @@ -14,12 +14,32 @@ #include #include "oslib/osfile.h" #include "oslib/wimp.h" +#include "netsurf/desktop/gui.h" #include "netsurf/desktop/selection.h" +#include "netsurf/desktop/textinput.h" #include "netsurf/riscos/gui.h" +#include "netsurf/riscos/message.h" +#include "netsurf/riscos/save.h" +#include "netsurf/riscos/textselection.h" +#include "netsurf/render/form.h" #include "netsurf/utils/log.h" #include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" +#ifndef wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX +#define wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX ((wimp_drag_claim_flags) 0x2u) +#endif + + + +/** Receive of Dragging message has claimed it */ +static bool dragging_claimed = false; +static wimp_t dragging_claimant; +static os_box dragging_box = { -34, -34, 34, 34 }; /* \todo - size properly */ +static wimp_drag_claim_flags last_claim_flags = 0; + + +static bool drag_claimed = false; static bool owns_clipboard = false; static bool owns_caret_and_selection = false; @@ -29,9 +49,10 @@ static char *clipboard = NULL; static size_t clip_alloc = 0; static size_t clip_length = 0; -static bool copy_handler(struct box *box, int offset, size_t length, - void *handle); +static bool copy_handler(const char *text, size_t length, bool space, + struct box *box, void *handle); static void ro_gui_discard_clipboard_contents(void); +static void ro_gui_dragging_bounced(wimp_message *message); /** @@ -166,30 +187,22 @@ void ro_gui_selection_drag_end(struct gui_window *g, wimp_dragged *drag) * Selection traversal routine for appending text to the current contents * of the clipboard. * - * \param box pointer to text box being (partially) added (or NULL for newline) - * \param offset start offset of text within box (bytes) - * \param length length of text to be appended (bytes) - * \param handle unused handle, we don't need one + * \param text pointer to text being added, or NULL for newline + * \param length length of text to be appended (bytes) + * \param space trailing space required after text + * \param box pointer to text box, or NULL if from textplain + * \param handle unused handle, we don't need one * \return true iff successful and traversal should continue */ -bool copy_handler(struct box *box, int offset, size_t length, void *handle) +bool copy_handler(const char *text, size_t length, bool space, + struct box *box, void *handle) { - bool space = false; - const char *text; - size_t len; - - if (box) { - len = min(length, box->length - offset); - text = box->text + offset; - if (box->space && length > len) space = true; - } - else { + if (!text) { text = "\n"; - len = 1; + length = 1; } - - return gui_add_to_clipboard(text, len, space); + return gui_add_to_clipboard(text, length, space); } @@ -483,3 +496,221 @@ bool ro_gui_save_clipboard(const char *path) } return true; } + + +/** + * Handler for Message_Dragging, used to implement auto-scrolling and + * ghost caret when a drag is in progress. + */ + +void ro_gui_selection_dragging(wimp_message *message) +{ + wimp_full_message_dragging *drag = (wimp_full_message_dragging*)message; + struct box *textarea = NULL; + struct box *text_box = NULL; + struct browser_window *bw; + wimp_window_state state; + struct content *content; + int gadget_box_x = 0; + int gadget_box_y = 0; + struct gui_window *g; + os_error *error; + int box_x = 0; + int box_y = 0; + int x, y; + +/* with autoscrolling, we will probably need to remember the gui_window and + override the drag->w window handle which could be any window on the desktop */ + g = ro_gui_window_lookup(drag->w); + + if ((drag->flags & wimp_DRAGGING_TERMINATE_DRAG) || !g) { + + if (drag_claimed) { + /* make sure that we erase the ghost caret */ + caret_remove(&ghost_caret); + } + + drag_claimed = false; + return; + } + + state.w = drag->w; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s\n", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + drag_claimed = false; + return; + } + + x = window_x_units(drag->pos.x, &state) / 2 / + g->option.scale; + y = -window_y_units(drag->pos.y, &state) / 2 / + g->option.scale; + + bw = g->bw; + content = bw->current_content; + if (content && content->type == CONTENT_HTML && + content->data.html.layout) { + + struct box *box = content->data.html.layout; + + while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) { + if (box->style && + box->style->visibility == CSS_VISIBILITY_HIDDEN) + continue; + + if (box->gadget) { + switch (box->gadget->type) { + + case GADGET_TEXTAREA: + textarea = box; + gadget_box_x = box_x; + gadget_box_y = box_y; + case GADGET_TEXTBOX: + case GADGET_PASSWORD: + text_box = box; + break; + + default: /* appease compiler */ + break; + } + } + } + } + + if (textarea) { + int pixel_offset; + int char_offset; + + /* draw/move the ghost caret */ + if (drag_claimed) + caret_remove(&ghost_caret); + else + gui_window_set_pointer(GUI_POINTER_CARET); + + text_box = textarea_get_position(textarea, x - gadget_box_x, + y - gadget_box_y, &char_offset, &pixel_offset); + + caret_set_position(&ghost_caret, bw, text_box, char_offset, pixel_offset); + drag_claimed = true; + } + else { + if (drag_claimed) { + /* make sure that we erase the ghost caret */ + caret_remove(&ghost_caret); + } + drag_claimed = false; + } + + if (drag_claimed) { + wimp_full_message_drag_claim claim; + os_error *error; + + claim.size = offsetof(wimp_full_message_drag_claim, file_types) + 8; + claim.your_ref = drag->my_ref; + claim.action = message_DRAG_CLAIM; + claim.flags = wimp_DRAG_CLAIM_POINTER_CHANGED | wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX; + claim.file_types[0] = osfile_TYPE_TEXT; + claim.file_types[1] = ~0; + + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)&claim, + drag->sender); + if (error) { + LOG(("xwimp_send_message: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + drag_claimed = true; + } +} + + + +/** + * Reset drag-and-drop state when drag completes (DataSave received) + */ + +void ro_gui_selection_drag_reset(void) +{ + caret_remove(&ghost_caret); + drag_claimed = false; +} + + +/** + * + */ + +void ro_gui_selection_drag_claim(wimp_message *message) +{ + wimp_full_message_drag_claim *claim = (wimp_full_message_drag_claim*)message; + + dragging_claimant = message->sender; + dragging_claimed = true; + + /* have we been asked to remove the drag box/sprite? */ + if (claim->flags & wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX) { + ro_gui_drag_box_cancel(); + } + else { + /* \todo - restore it here? */ + } + + /* do we need to restore the default pointer shape? */ + if ((last_claim_flags & wimp_DRAG_CLAIM_POINTER_CHANGED) && + !(claim->flags & wimp_DRAG_CLAIM_POINTER_CHANGED)) { + gui_window_set_pointer(GUI_POINTER_DEFAULT); + } + + last_claim_flags = claim->flags; +} + + +void ro_gui_selection_send_dragging(wimp_pointer *pointer) +{ + wimp_full_message_dragging dragmsg; + + LOG(("sending DRAGGING to %p, %d", pointer->w, pointer->i)); + + dragmsg.size = offsetof(wimp_full_message_dragging, file_types) + 8; + dragmsg.your_ref = 0; + dragmsg.action = message_DRAGGING; + dragmsg.w = pointer->w; + dragmsg.i = pointer->i; + dragmsg.pos = pointer->pos; +/* \todo - this is interesting because it depends upon not just the state of the + shift key, but also whether it /can/ be deleted, ie. from text area/input + rather than page contents */ + dragmsg.flags = wimp_DRAGGING_FROM_SELECTION; + dragmsg.box = dragging_box; + dragmsg.file_types[0] = osfile_TYPE_TEXT; + dragmsg.file_types[1] = ~0; + + /* if the message_dragmsg messages have been claimed we must address them + to the claimant task, which is not necessarily the task that owns whatever + window happens to be under the pointer */ + + if (dragging_claimed) { + ro_message_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message*)&dragmsg, dragging_claimant, ro_gui_dragging_bounced); + } + else { + ro_message_send_message_to_window(wimp_USER_MESSAGE_RECORDED, + (wimp_message*)&dragmsg, pointer->w, pointer->i, + ro_gui_dragging_bounced, &dragging_claimant); + } +} + + +/** + * Our message_DRAGGING message was bounced, ie. the intended recipient does not + * support the drag-and-drop protocol or cannot receive the data at the pointer + * position. + */ + +void ro_gui_dragging_bounced(wimp_message *message) +{ + dragging_claimed = false; +} diff --git a/riscos/ucstables.c b/riscos/ucstables.c index 92b9121f9..ffe92be30 100644 --- a/riscos/ucstables.c +++ b/riscos/ucstables.c @@ -451,7 +451,8 @@ utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len, const char *enc; utf8_convert_ret err; - assert(string && result); + assert(string); + assert(result); /* get length, if necessary */ if (len == 0) diff --git a/riscos/wimp.c b/riscos/wimp.c index e9188aeb9..fa667d1d6 100644 --- a/riscos/wimp.c +++ b/riscos/wimp.c @@ -849,32 +849,3 @@ bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask) { } return state.flags & mask; } - - -/** - * Open/move a window to the front of the window stack. - */ - -bool ro_gui_open_window_at_front(wimp_w w) { - wimp_window_state state; - os_error *error; - - state.w = w; - 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; - } - - state.next = wimp_TOP; - error = xwimp_open_window((wimp_open*)&state); - if (error) { - LOG(("xwimp_open_window: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - return false; - } - return true; -} diff --git a/riscos/wimp.h b/riscos/wimp.h index 35a1ddc30..a7777d28d 100644 --- a/riscos/wimp.h +++ b/riscos/wimp.h @@ -59,6 +59,5 @@ void ro_gui_user_redraw(wimp_draw *redraw, bool user_fill, os_colour user_colour void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask, wimp_window_flags xor_mask); bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask); -bool ro_gui_open_window_at_front(wimp_w w); #endif -- cgit v1.2.3