From 4e7edf00e217bc05ab6c0b45bcf9e9d843f99f32 Mon Sep 17 00:00:00 2001 From: John-Mark Bell Date: Sun, 13 Jan 2013 18:18:49 +0000 Subject: Fix 1912552: move FontRemove into ro_gui_cleanup() --- riscos/gui.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'riscos/gui.c') diff --git a/riscos/gui.c b/riscos/gui.c index 8eac42de7..de5dc4af4 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -944,6 +944,8 @@ void ro_gui_cleanup(void) { ro_gui_buffer_close(); xhourglass_off(); + /* Uninstall NetSurf-specific fonts */ + xos_cli("FontRemove NetSurf:Resources.Fonts."); } -- cgit v1.2.3 From 64ae9e8693aaaf09cb4e35b63d029d446ef361b0 Mon Sep 17 00:00:00 2001 From: John-Mark Bell Date: Tue, 22 Jan 2013 08:51:58 +0000 Subject: Fix paste. Store clipboard as UTF-8 internally, to avoid unnecessary data loss when copying internally. --- riscos/gui.c | 37 +++++++- riscos/textselection.c | 232 ++++++++++++++++++++++++++++++++++++++----------- riscos/textselection.h | 8 ++ riscos/window.c | 11 ++- 4 files changed, 234 insertions(+), 54 deletions(-) (limited to 'riscos/gui.c') diff --git a/riscos/gui.c b/riscos/gui.c index de5dc4af4..e786f67d8 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -1282,6 +1282,22 @@ void ro_gui_drag_end(wimp_dragged *drag) * Handle Key_Pressed events. */ +static void ro_gui_keypress_cb(void *pw) +{ + wimp_key *key = (wimp_key *) pw; + + if (ro_gui_wimp_event_keypress(key) == false) { + os_error *error = xwimp_process_key(key->c); + if (error) { + LOG(("xwimp_process_key: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + } + + free(key); +} + void ro_gui_keypress(wimp_key *key) { if (key->c == wimp_KEY_ESCAPE && @@ -1292,8 +1308,17 @@ void ro_gui_keypress(wimp_key *key) (easier than finding somewhere safe to abort the drag) */ ro_gui_drag_box_cancel(); gui_current_drag_type = GUI_DRAG_NONE; - } - else if (!ro_gui_wimp_event_keypress(key)) { + } else if (key->c == 22 /* Ctrl-V */) { + wimp_key *copy; + + /* Must copy the keypress as it's on the stack */ + copy = malloc(sizeof(wimp_key)); + if (copy == NULL) + return; + memcpy(copy, key, sizeof(wimp_key)); + + ro_gui_selection_prepare_paste(key->w, ro_gui_keypress_cb, copy); + } else if (ro_gui_wimp_event_keypress(key) == false) { os_error *error = xwimp_process_key(key->c); if (error) { LOG(("xwimp_process_key: 0x%x: %s", @@ -1320,9 +1345,10 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message) if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) { if (ro_print_current_window) ro_print_dataload_bounce(message); - } - else + } else if (ro_gui_selection_prepare_paste_dataload( + (wimp_full_message_data_xfer *) message) == false) { ro_msg_dataload(message); + } break; case message_DATA_LOAD_ACK: @@ -1772,6 +1798,9 @@ void ro_msg_datasave(wimp_message *message) ro_msg_terminate_filename(dataxfer); + if (ro_gui_selection_prepare_paste_datasave(dataxfer)) + return; + switch (dataxfer->file_type) { case FILETYPE_ACORN_URI: case FILETYPE_ANT_URL: diff --git a/riscos/textselection.c b/riscos/textselection.c index d1d4340b7..0cb8eb2c0 100644 --- a/riscos/textselection.c +++ b/riscos/textselection.c @@ -56,11 +56,17 @@ static bool drag_claimed = false; static bool owns_clipboard = false; static bool owns_caret_and_selection = false; -/* current clipboard contents if we own the clipboard */ +/* Current clipboard contents if we own the clipboard + * Current paste buffer if we don't + */ static char *clipboard = NULL; -static size_t clip_alloc = 0; static size_t clip_length = 0; +/* Paste context */ +static ro_gui_selection_prepare_paste_cb paste_cb = NULL; +static void *paste_cb_pw = NULL; +static int paste_prev_message = 0; + static void ro_gui_discard_clipboard_contents(void); static void ro_gui_dragging_bounced(wimp_message *message); @@ -207,22 +213,21 @@ void gui_clear_selection(struct gui_window *g) void gui_set_clipboard(const char *buffer, size_t length, nsclipboard_styles styles[], int n_styles) { - utf8_convert_ret res; char *new_cb; if (length == 0) return; - /* Convert to local encoding */ - res = utf8_to_local_encoding(buffer, length, &new_cb); - - if (res != UTF8_CONVERT_OK || new_cb == NULL) + new_cb = malloc(length); + if (new_cb == NULL) return; - /* Replace existing clipboard contents with converted text */ + memcpy(new_cb, buffer, length); + + /* Replace existing clipboard contents */ free(clipboard); clipboard = new_cb; - clip_alloc = clip_length = strlen(new_cb); + clip_length = length; if (!owns_clipboard) { /* Tell RO we now own clipboard */ @@ -253,7 +258,7 @@ void gui_set_clipboard(const char *buffer, size_t length, /** * Core asks front end for clipboard contents. * - * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core + * \param buffer UTF-8 text, allocated by front end, ownership yielded to core * \param length Byte length of UTF-8 text in buffer */ void gui_get_clipboard(char **buffer, size_t *length) @@ -261,64 +266,180 @@ void gui_get_clipboard(char **buffer, size_t *length) *buffer = NULL; *length = 0; - if (owns_clipboard) { - if (clip_length > 0) { - char *utf8; - utf8_convert_ret ret; - /* Clipboard is in local encoding so - * convert to UTF8 */ - ret = utf8_from_local_encoding(clipboard, - clip_length, &utf8); - if (ret == UTF8_CONVERT_OK) { - *buffer = utf8; - *length = strlen(utf8); - } + if (clip_length > 0) { + char *cb = malloc(clip_length); + if (cb != NULL) { + memcpy(cb, clipboard, clip_length); + *buffer = cb; + *length = clip_length; } - } else { - /** TODO: Handle case when we don't own the clipboard */ + } +} + -/* http://www.starfighter.acornarcade.com/mysite/articles/SelectionModel.html +/** + * Discard the current contents of the clipboard, if any, releasing the + * memory it uses. */ -/* wimp_full_message_data_request msg; - os_error *error; - os_coord pos; +void ro_gui_discard_clipboard_contents(void) +{ + free(clipboard); + clip_length = 0; +} + - if (!ro_gui_window_to_screen_pos(g, x, y, &pos)) - return; +static void ro_gui_selection_prepare_paste_complete(void) +{ + ro_gui_selection_prepare_paste_cb cb = paste_cb; + void *pw = paste_cb_pw; + + paste_cb = NULL; + paste_cb_pw = NULL; + paste_prev_message = 0; + + cb(pw); +} + +static void ro_gui_selection_prepare_paste_bounced(wimp_message *message) +{ + ro_gui_selection_prepare_paste_complete(); +} + +/** + * Prepare to paste data from another application + * + * \param w Window being pasted into + * \param cb Callback to call once preparation is complete + * \param pw Private data for callback + */ + +void ro_gui_selection_prepare_paste(wimp_w w, + ro_gui_selection_prepare_paste_cb cb, void *pw) +{ + if (owns_clipboard) { + /* We own the clipboard: we're already prepared */ + cb(pw); + } else { + /* Someone else owns the clipboard: request its contents */ + wimp_full_message_data_request msg; + bool success; + + ro_gui_discard_clipboard_contents(); msg.size = sizeof(msg); msg.your_ref = 0; msg.action = message_DATA_REQUEST; - msg.w = g->window; + msg.w = w; msg.i = -1; - msg.pos.x = pos.x; - msg.pos.y = pos.y; + msg.pos.x = 0; + msg.pos.y = 0; 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); + success = ro_message_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *) &msg, wimp_BROADCAST, + ro_gui_selection_prepare_paste_bounced); + if (success == false) { + /* Ensure key is handled, anyway */ + cb(pw); + } else { + /* Set up paste context */ + paste_cb = cb; + paste_cb_pw = pw; + paste_prev_message = msg.my_ref; } -*/ } + } } - /** - * Discard the current contents of the clipboard, if any, releasing the - * memory it uses. + * Prepare to paste data from another application (step 2) + * + * \param dataxfer DataSave message + * \return True if message was handled, false otherwise */ +bool ro_gui_selection_prepare_paste_datasave( + wimp_full_message_data_xfer *dataxfer) +{ + bool success; -void ro_gui_discard_clipboard_contents(void) + /* Ignore messages that aren't for us */ + if (dataxfer->your_ref == 0 || dataxfer->your_ref != paste_prev_message) + return false; + + /* We're done if the paste data isn't text */ + if (dataxfer->file_type != osfile_TYPE_TEXT) { + ro_gui_selection_prepare_paste_complete(); + return true; + } + + /* Generate and send DataSaveAck */ + dataxfer->your_ref = dataxfer->my_ref; + dataxfer->size = offsetof(wimp_full_message_data_xfer, file_name) + 16; + dataxfer->action = message_DATA_SAVE_ACK; + dataxfer->est_size = -1; + memcpy(dataxfer->file_name, "", SLEN("") + 1); + + success = ro_message_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *) dataxfer, dataxfer->sender, + ro_gui_selection_prepare_paste_bounced); + if (success == false) { + ro_gui_selection_prepare_paste_complete(); + } else { + paste_prev_message = dataxfer->my_ref; + } + + return true; +} + + +/** + * Prepare to paste data from another application (step 3) + * + * \param dataxfer DataLoad message + * \return True if message was handled, false otherwise + */ +bool ro_gui_selection_prepare_paste_dataload( + wimp_full_message_data_xfer *dataxfer) { - if (clip_alloc) free(clipboard); - clip_alloc = 0; - clip_length = 0; + FILE *fp; + long size; + char *local_cb; + utf8_convert_ret ret; + + /* Ignore messages that aren't for us */ + if (dataxfer->your_ref == 0 || dataxfer->your_ref != paste_prev_message) + return false; + + fp = fopen(dataxfer->file_name, "r"); + if (fp != NULL) { + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + local_cb = malloc(size); + if (local_cb != NULL) { + fread(local_cb, 1, size, fp); + + fclose(fp); + + ret = utf8_from_local_encoding(local_cb, size, + &clipboard); + if (ret == UTF8_CONVERT_OK) { + clip_length = strlen(clipboard); + } + } + } + + /* Send DataLoadAck */ + dataxfer->action = message_DATA_LOAD_ACK; + dataxfer->your_ref = dataxfer->my_ref; + ro_message_send_message(wimp_USER_MESSAGE, + (wimp_message *) dataxfer, dataxfer->sender, NULL); + + ro_gui_selection_prepare_paste_complete(); + return true; } @@ -398,18 +519,31 @@ void ro_gui_selection_data_request(wimp_full_message_data_request *req) bool ro_gui_save_clipboard(const char *path) { + char *local_cb; + utf8_convert_ret ret; os_error *error; assert(clip_length > 0 && clipboard); + + ret = utf8_to_local_encoding(clipboard, clip_length, &local_cb); + if (ret != UTF8_CONVERT_OK) { + warn_user("SaveError", "Could not convert"); + return false; + } + error = xosfile_save_stamped(path, osfile_TYPE_TEXT, - (byte*)clipboard, - (byte*)clipboard + clip_length); + (byte*) local_cb, + (byte*) local_cb + strlen(local_cb)); + + free(local_cb); + if (error) { LOG(("xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess)); warn_user("SaveError", error->errmess); return false; } + return true; } diff --git a/riscos/textselection.h b/riscos/textselection.h index 544636ec2..a3763b46e 100644 --- a/riscos/textselection.h +++ b/riscos/textselection.h @@ -26,6 +26,14 @@ #include "oslib/wimp.h" #include "desktop/gui.h" +typedef void (*ro_gui_selection_prepare_paste_cb)(void *pw); + +void ro_gui_selection_prepare_paste(wimp_w w, + ro_gui_selection_prepare_paste_cb cb, void *pw); +bool ro_gui_selection_prepare_paste_datasave( + wimp_full_message_data_xfer *dataxfer); +bool ro_gui_selection_prepare_paste_dataload( + wimp_full_message_data_xfer *dataxfer); 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); diff --git a/riscos/window.c b/riscos/window.c index 535105459..2f8bec614 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -74,6 +74,7 @@ #include "riscos/oslib_pre7.h" #include "riscos/save.h" #include "riscos/content-handlers/sprite.h" +#include "riscos/textselection.h" #include "riscos/toolbar.h" #include "riscos/thumbnail.h" #include "riscos/url_complete.h" @@ -2600,6 +2601,14 @@ void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, } +static void ro_gui_window_paste_cb(void *pw) +{ + struct browser_window *bw = pw; + + browser_window_key_press(bw, KEY_PASTE); +} + + /** * Handle selections from a browser window menu * @@ -2833,7 +2842,7 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, browser_window_key_press(bw, KEY_CUT_SELECTION); break; case BROWSER_SELECTION_PASTE: - browser_window_key_press(bw, KEY_PASTE); + ro_gui_selection_prepare_paste(w, ro_gui_window_paste_cb, bw); break; case BROWSER_SELECTION_ALL: browser_window_key_press(bw, KEY_SELECT_ALL); -- cgit v1.2.3