NetSurf
save.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
3 * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * \file
22 * Save dialog and drag and drop saving implementation for RISC OS.
23 */
24
25#include <assert.h>
26#include <ctype.h>
27#include <errno.h>
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include "oslib/dragasprite.h"
33#include "oslib/osbyte.h"
34#include "oslib/osfile.h"
35#include "oslib/osmodule.h"
36#include "oslib/osspriteop.h"
37#include "oslib/wimp.h"
38#include "oslib/wimpspriteop.h"
39
40#include "utils/config.h"
41#include "utils/log.h"
42#include "utils/messages.h"
43#include "utils/nsoption.h"
44#include "utils/nsurl.h"
45#include "utils/utf8.h"
46#include "utils/utils.h"
48#include "netsurf/window.h"
49#include "netsurf/bitmap.h"
50#include "netsurf/content.h"
51#include "netsurf/form.h"
52#include "desktop/hotlist.h"
54#include "desktop/version.h"
56#include "desktop/save_text.h"
57
58#include "riscos/bitmap.h"
59#include "riscos/dialog.h"
60#include "riscos/gui.h"
61#include "riscos/window.h"
62#include "riscos/menus.h"
63#include "riscos/message.h"
64#include "riscos/mouse.h"
65#include "riscos/query.h"
66#include "riscos/save.h"
67#include "riscos/save_draw.h"
68#include "riscos/save_pdf.h"
70#include "riscos/wimp.h"
71#include "riscos/wimp_event.h"
72#include "riscos/ucstables.h"
73#include "riscos/filetype.h"
74
75//typedef enum
76//{
77// QueryRsn_Quit,
78// QueryRsn_Abort,
79// QueryRsn_Overwrite
80//} query_reason;
81
82
83/**
84 * \todo much of the state information for a save should probably be
85 * moved into a structure now since we could have multiple saves
86 * outstanding.
87 */
88
90static struct hlcache_handle *gui_save_content = NULL;
91static char *gui_save_selection = NULL;
92static const char *gui_save_url = NULL;
93static const char *gui_save_title = NULL;
97static wimp_message gui_save_message;
98static bool gui_save_close_after = true;
99
100static bool dragbox_active = false; /** in-progress Wimp_DragBox/DragASprite op */
101static bool using_dragasprite = true;
102static bool saving_from_dialog = true;
103static osspriteop_area *saveas_area = NULL;
104static wimp_w gui_save_sourcew = (wimp_w)-1;
105#define LEAFNAME_MAX 200
107
108/** Current save directory (updated by and used for dialog-based saving) */
109static char *save_dir = NULL;
110static size_t save_dir_len;
111
113
114/** An entry in gui_save_table. */
117 const char *name;
118};
119
120/**
121 * Table of filetypes and default filenames. Must be in sync with
122 * gui_save_type (riscos/gui.h). A filetype of 0 indicates the content should
123 * be used.
124 */
125static const struct gui_save_table_entry gui_save_table[] = {
126 /* GUI_SAVE_SOURCE, */ { 0, "SaveSource" },
127 /* GUI_SAVE_DRAW, */ { 0xaff, "SaveDraw" },
128 /* GUI_SAVE_PDF, */ { 0xadf, "SavePDF" },
129 /* GUI_SAVE_TEXT, */ { 0xfff, "SaveText" },
130 /* GUI_SAVE_COMPLETE, */ { 0xfaf, "SaveComplete" },
131 /* GUI_SAVE_OBJECT_ORIG, */ { 0, "SaveObject" },
132 /* GUI_SAVE_OBJECT_NATIVE, */ { 0, "SaveObject" },
133 /* GUI_SAVE_LINK_URI, */ { 0xf91, "SaveLink" },
134 /* GUI_SAVE_LINK_URL, */ { 0xb28, "SaveLink" },
135 /* GUI_SAVE_LINK_TEXT, */ { 0xfff, "SaveLink" },
136 /* GUI_SAVE_HOTLIST_EXPORT_HTML, */ { 0xfaf, "Hotlist" },
137 /* GUI_SAVE_HISTORY_EXPORT_HTML, */ { 0xfaf, "History" },
138 /* GUI_SAVE_TEXT_SELECTION, */ { 0xfff, "SaveSelection" },
139};
140
141
142static bool ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite);
143
144
145/**
146 * Create the saveas dialogue from the given template, and the sprite area
147 * necessary for our thumbnail (full page save)
148 *
149 * \param template_name name of template to be used
150 * \return window handle of created dialogue
151 */
152wimp_w ro_gui_saveas_create(const char *template_name)
153{
154 const int sprite_size = (68 * 68 * 4) + ((68 * 68) / 8); /* 32bpp with mask */
155 int area_size = sizeof(osspriteop_area) + sizeof(osspriteop_header) +
156 256 * 8 + sprite_size;
157 void *area = NULL;
158 wimp_window *window;
159 os_error *error;
160 wimp_icon *icons;
161 wimp_w w;
162
163 window = ro_gui_dialog_load_template(template_name);
164 assert(window);
165
166 icons = window->icons;
167
168 error = xosmodule_alloc(area_size, (void **) &area);
169 if (error) {
170 NSLOG(netsurf, INFO, "xosmodule_alloc: 0x%x: %s",
171 error->errnum, error->errmess);
172 xwimp_close_template();
173 die(error->errmess);
174 } else {
175 saveas_area = area;
176 saveas_area->size = area_size;
177 saveas_area->first = 16;
178
179 error = xosspriteop_clear_sprites(osspriteop_USER_AREA, saveas_area);
180 if (error) {
181 NSLOG(netsurf, INFO,
182 "xosspriteop_clear_sprites: 0x%x: %s",
183 error->errnum,
184 error->errmess);
185 ro_warn_user("MiscError", error->errmess);
186
187 xosmodule_free(saveas_area);
188 saveas_area = NULL;
189 }
190 }
191
192 assert((icons[ICON_SAVE_ICON].flags &
193 (wimp_ICON_TEXT | wimp_ICON_SPRITE | wimp_ICON_INDIRECTED)) ==
194 (wimp_ICON_SPRITE | wimp_ICON_INDIRECTED));
195 icons[ICON_SAVE_ICON].data.indirected_sprite.area = saveas_area;
196
197 /* create window */
198 error = xwimp_create_window(window, &w);
199 if (error) {
200 NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
201 error->errnum, error->errmess);
202 xwimp_close_template();
203 die(error->errmess);
204 }
205
206 /* the window definition is copied by the wimp and may be freed */
207 free(window);
208
209 return w;
210}
211
212
213/**
214 * Clean-up function that releases our sprite area and memory.
215 */
217{
218 if (saveas_area) {
219 os_error *error = xosmodule_free(saveas_area);
220 if (error) {
221 NSLOG(netsurf, INFO, "xosmodule_free: 0x%x: %s",
222 error->errnum, error->errmess);
223 ro_warn_user("MiscError", error->errmess);
224 }
225 saveas_area = NULL;
226 }
227
228 free(save_dir);
229 save_dir = NULL;
230}
231
232
233/**
234 * Create a thumbnail sprite for the page being saved.
235 *
236 * \param h content to be converted
237 * \param name sprite name to use
238 * \return true iff successful
239 */
240static bool
242{
243 osspriteop_header *sprite_header;
244 struct bitmap *bitmap;
245 osspriteop_area *area;
246
248 if (!bitmap) {
249 NSLOG(netsurf, INFO, "Thumbnail initialisation failed.");
250 return false;
251 }
255 if (!area) {
256 NSLOG(netsurf, INFO, "Thumbnail conversion failed.");
257 return false;
258 }
259
260 sprite_header = (osspriteop_header *)(area + 1);
261 memset(sprite_header->name, 0, 12);
262 memcpy(sprite_header->name, name, min(strlen(name), 12));
263
264
265 /* we can't resize the saveas sprite area because it may move
266 * and we have no elegant way to update the window definition
267 * on all OS versions
268 */
269 assert(sprite_header->size <= saveas_area->size - saveas_area->first);
270
271 memcpy((byte*)saveas_area + saveas_area->first,
272 sprite_header, sprite_header->size);
273
274 saveas_area->sprite_count = 1;
275 saveas_area->used = saveas_area->first + sprite_header->size;
276
277 free(area);
278
279 return true;
280}
281
282
283/**
284 * Suggest a leafname and sprite name for the given content.
285 *
286 * \param h content being saved
287 * \param save_type type of save operation being performed
288 * \param url used to determine leafname
289 * \param leaf_buf buffer to receive suggested leafname.
290 * \param leaf_len size of buffer to receive suggested leafname.
291 * \param icon_buf buffer to receive sprite name.
292 * \param icon_len size of buffer to receive icon name.
293 */
294static void
296 const nsurl *url, char *leaf_buf, size_t leaf_len,
297 char *icon_buf, size_t icon_len)
298{
299 /* filename */
300 const char *name = gui_save_table[save_type].name;
301 bool done = false;
302 char *nice = NULL;
303 nserror err;
304 char *local_name;
305
306 assert(icon_len >= 13);
307
308 /* parameters that we need to remember */
309 gui_save_current_type = save_type;
311
312 /* suggest a filetype based upon the content */
314 if (!gui_save_filetype && h) {
315 if (save_type == GUI_SAVE_OBJECT_NATIVE) {
316 switch (ro_content_native_type(h)) {
317 case osfile_TYPE_SPRITE:
318 gui_save_filetype = osfile_TYPE_SPRITE;
319 break;
320 case osfile_TYPE_DRAW:
321 gui_save_filetype = osfile_TYPE_DRAW;
322 break;
323 default:
324 break;
325 }
326 }
329 }
330
331 /* leafname */
332 if ((url != NULL) &&
333 (nsurl_nice(url, &nice, nsoption_bool(strip_extensions)) ==
334 NSERROR_OK)) {
335 size_t i;
336 for (i = 0; nice[i]; i++) {
337 if (nice[i] == '.')
338 nice[i] = '/';
339 else if (nice[i] <= ' ' ||
340 strchr(":*#$&@^%\\", nice[i]))
341 nice[i] = '_';
342 }
343 name = nice;
344 } else {
345 name = messages_get(name);
346 }
347
348 /* filename is utf8 */
349 if (save_type == GUI_SAVE_COMPLETE && leaf_len > 0) {
350 leaf_buf[0] = '!';
351 leaf_buf++;
352 leaf_len--;
353 }
354 strncpy(leaf_buf, name, leaf_len);
355 leaf_buf[leaf_len - 1] = 0;
356
357 err = utf8_to_local_encoding(name, 0, &local_name);
358 if (err != NSERROR_OK) {
359 /* badenc should never happen */
360 assert(err != NSERROR_BAD_ENCODING);
361 local_name = NULL;
362 }
363
364 if (local_name != NULL)
365 name = local_name;
366
367 /* sprite name used for icon and dragging */
368 if (save_type == GUI_SAVE_COMPLETE) {
369 int index;
370
371 /* Paint gets confused with uppercase characters and we need to
372 convert spaces to hard spaces */
373 icon_buf[0] = '!';
374 for (index = 0; index < 11 && name[index]; ) {
375 char ch = name[index];
376 if (ch == ' ')
377 icon_buf[++index] = 0xa0;
378 else
379 icon_buf[++index] = tolower(ch);
380 }
381 memset(&icon_buf[index + 1], 0, 11 - index);
382 icon_buf[12] = '\0';
383
384 if (ro_gui_save_create_thumbnail(h, icon_buf))
385 done = true;
386 }
387
388 if (!done) {
389 osspriteop_header *sprite;
390 os_error *error;
391
392 sprintf(icon_buf, "file_%.3x", gui_save_filetype);
393
394 error = ro_gui_wimp_get_sprite(icon_buf, &sprite);
395 if (error && error->errnum == error_SPRITE_OP_DOESNT_EXIST) {
396 /* try the 'unknown' filetype sprite as a fallback */
397 memcpy(icon_buf, "file_xxx", 9);
398 error = ro_gui_wimp_get_sprite(icon_buf, &sprite);
399 }
400
401 if (error) {
402 NSLOG(netsurf, INFO,
403 "ro_gui_wimp_get_sprite: 0x%x: %s",
404 error->errnum,
405 error->errmess);
406 ro_warn_user("MiscError", error->errmess);
407 } else {
408 /* the sprite area should always be large enough for
409 * file_xxx sprites */
410 assert(sprite->size <= saveas_area->size -
411 saveas_area->first);
412
413 memcpy((byte*)saveas_area + saveas_area->first,
414 sprite,
415 sprite->size);
416
417 saveas_area->sprite_count = 1;
418 saveas_area->used = saveas_area->first + sprite->size;
419 }
420 }
421
422 free(local_name);
423 free(nice);
424}
425
426
427/**
428 * Prepares the save box to reflect gui_save_type and a content, and
429 * opens it.
430 *
431 * \param save_type type of save
432 * \param h content to save
433 * \param s selection to save
434 * \param url url to be saved (link types)
435 * \param title title (if any), when saving links
436 */
438 char *s, const nsurl *url, const char *title)
439{
440 char name_buf[FILENAME_MAX];
441 size_t leaf_offset = 0;
442 char icon_buf[20];
443
444 assert( (save_type == GUI_SAVE_LINK_URI) ||
445 (save_type == GUI_SAVE_LINK_URL) ||
446 (save_type == GUI_SAVE_LINK_TEXT) ||
447 (save_type == GUI_SAVE_HOTLIST_EXPORT_HTML) ||
448 (save_type == GUI_SAVE_HISTORY_EXPORT_HTML) ||
449 (save_type == GUI_SAVE_TEXT_SELECTION) || h);
450
451 if (gui_save_selection == NULL)
452 free(gui_save_selection);
453
455 if (url != NULL) {
457 } else {
458 gui_save_url = NULL;
459 }
461
462 if (save_dir) {
463 leaf_offset = save_dir_len;
464 memcpy(name_buf, save_dir, leaf_offset);
465 name_buf[leaf_offset++] = '.';
466 }
467
468 if (h != NULL) {
470 }
471
472 ro_gui_save_set_state(h, save_type, url,
473 name_buf + leaf_offset, FILENAME_MAX - leaf_offset,
474 icon_buf, sizeof(icon_buf));
475
477 icon_buf);
478
481}
482
483
484/**
485 * Handle lack of Message_DataSaveAck for drags, saveas dialogs and clipboard code
486 *
487 * \param message A wimp message.
488 */
489static void ro_gui_save_bounced(wimp_message *message)
490{
492}
493
494
495/**
496 * Handle User_Drag_Box event for a drag from the save dialog or browser window.
497 *
498 * \param *drag The Wimp_DragEnd data block.
499 * \param *data NULL, as function is used as a callback from ro_mouse.
500 */
501static void ro_gui_save_drag_end(wimp_dragged *drag, void *data)
502{
503 const char *name;
504 wimp_pointer pointer;
505 wimp_message message;
506 os_error *error;
507 char *dp, *ep;
508 char *local_name = NULL;
509
510 if (dragbox_active)
512
513 error = xwimp_get_pointer_info(&pointer);
514 if (error) {
515 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
516 error->errnum, error->errmess);
517 ro_warn_user("WimpError", error->errmess);
518 return;
519 }
520
521 /* perform hit-test if the destination is the same as the
522 * source window; we want to allow drag-saving from a page
523 * into the input fields within the page, but avoid accidental
524 * replacements of the current page
525 */
526 if (gui_save_sourcew != (wimp_w)-1 && pointer.w == gui_save_sourcew) {
527 int dx = (drag->final.x1 + drag->final.x0)/2;
528 int dy = (drag->final.y1 + drag->final.y0)/2;
529 struct gui_window *g;
530 bool dest_ok = false;
531 os_coord pos;
532
534
535 if (g && ro_gui_window_to_window_pos(g, dx, dy, &pos)) {
537 pos.x, pos.y, NULL);
538 }
539 if (!dest_ok)
540 return;
541 }
542
543 if (!saving_from_dialog) {
544 /* saving directly from browser window, choose a
545 * name based upon the URL */
546 nserror err;
547 err = utf8_to_local_encoding(save_leafname, 0, &local_name);
548 if (err != NSERROR_OK) {
549 /* badenc should never happen */
550 assert(err != NSERROR_BAD_ENCODING);
551 local_name = NULL;
552 }
553 name = local_name ? local_name : save_leafname;
554 }
555 else {
556 char *dot;
557
558 /* saving from dialog, grab leafname from icon */
560 dot = strrchr(name, '.');
561 if (dot)
562 name = dot + 1;
563 }
564
565 dp = message.data.data_xfer.file_name;
566 ep = dp + sizeof message.data.data_xfer.file_name;
567
569 message.data.data_xfer.file_type = 0x2000;
570 if (*name != '!') *dp++ = '!';
571 } else
572 message.data.data_xfer.file_type = gui_save_filetype;
573
574 ro_gui_convert_save_path(dp, ep - dp, name);
575
576 /** \todo we're supposed to set this if drag-n-drop used */
577 message.your_ref = 0;
578
579 message.action = message_DATA_SAVE;
580 message.data.data_xfer.w = pointer.w;
581 message.data.data_xfer.i = pointer.i;
582 message.data.data_xfer.pos.x = pointer.pos.x;
583 message.data.data_xfer.pos.y = pointer.pos.y;
584 message.data.data_xfer.est_size = 1000;
585 message.size = 44 + ((strlen(message.data.data_xfer.file_name) + 4) &
586 (~3u));
587
588 ro_message_send_message_to_window(wimp_USER_MESSAGE_RECORDED, &message,
589 pointer.w, pointer.i, ro_gui_save_bounced, NULL);
590
592
593 free(local_name);
594}
595
596
597/**
598 * Starts a drag for the save dialog
599 *
600 * \param pointer mouse position info from Wimp
601 */
602void ro_gui_save_start_drag(wimp_pointer *pointer)
603{
604 if (pointer->buttons & (wimp_DRAG_SELECT | wimp_DRAG_ADJUST)) {
605 const char *sprite = ro_gui_get_icon_string(pointer->w, pointer->i);
606 int x = pointer->pos.x, y = pointer->pos.y;
607 wimp_window_state wstate;
608 wimp_icon_state istate;
609 /* start the drag from the icon's exact location, rather than the pointer */
610 istate.w = wstate.w = pointer->w;
611 istate.i = pointer->i;
612 if (!xwimp_get_window_state(&wstate) && !xwimp_get_icon_state(&istate)) {
613 x = (istate.icon.extent.x1 + istate.icon.extent.x0)/2 +
614 wstate.visible.x0 - wstate.xscroll;
615 y = (istate.icon.extent.y1 + istate.icon.extent.y0)/2 +
616 wstate.visible.y1 - wstate.yscroll;
617 }
618 ro_mouse_drag_start(ro_gui_save_drag_end, NULL, NULL, NULL);
619 gui_save_sourcew = pointer->w;
620 saving_from_dialog = true;
621 gui_save_close_after = !(pointer->buttons & wimp_DRAG_ADJUST);
622 ro_gui_drag_icon(x, y, sprite);
623 }
624}
625
626
627/**
628 * Save completed, inform recipient and close our 'save as' dialog.
629 */
630static void ro_gui_save_done(void)
631{
632 os_error *error;
633
635 /* Ack successful save with message_DATA_LOAD */
636 wimp_message *message = &gui_save_message;
637 message->action = message_DATA_LOAD;
638 message->your_ref = message->my_ref;
639 error = xwimp_send_message(wimp_USER_MESSAGE, message,
640 message->sender);
641 if (error) {
642 NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
643 error->errnum, error->errmess);
644 ro_warn_user("SaveError", error->errmess);
645 }
646 }
647
648 if (saving_from_dialog) {
649 /* remember the save directory if saving to the Filer */
651 gui_save_message.data.data_xfer.est_size != -1) {
652 char *sp = gui_save_message.data.data_xfer.file_name;
653 char *ep = sp + sizeof(gui_save_message.data.data_xfer.file_name);
654 char *lastdot = NULL;
655 char *p = sp;
656
657 while (p < ep && *p >= 0x20) {
658 if (*p == '.') {
659 /* don't remember the directory if it's a temporary file */
660 if (!lastdot && p == sp + 12 &&
661 !memcmp(sp, "<Wimp$Scrap>", 12)) break;
662 lastdot = p;
663 }
664 p++;
665 }
666 if (lastdot) {
667 /* remember the directory */
668 char *new_dir = realloc(save_dir, (lastdot+1)-sp);
669 if (new_dir) {
670 save_dir_len = lastdot - sp;
671 memcpy(new_dir, sp, save_dir_len);
672 new_dir[save_dir_len] = '\0';
673 save_dir = new_dir;
674 }
675 }
676 }
677
679 /* Close the save window */
681 error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
682 if (error) {
683 NSLOG(netsurf, INFO,
684 "xwimp_create_menu: 0x%x: %s",
685 error->errnum,
686 error->errmess);
687 ro_warn_user("MenuError", error->errmess);
688 }
689 }
690 }
691
694}
695
696
697/**
698 * User has opted not to overwrite the existing file.
699 */
700static void
702{
703 if (!saving_from_dialog) {
704// ro_gui_save_prepare(gui_save_current_type, gui_save_content);
705// ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
706 }
707}
708
709
710/**
711 * Overwrite of existing file confirmed, proceed with the save.
712 */
713static void
715{
716 if (ro_gui_save_content(gui_save_content, gui_save_message.data.data_xfer.file_name, true)) {
718 }
719}
720
721
722/**
723 * Save a link file.
724 *
725 * \param url url to be saved
726 * \param title corresponding title, if any
727 * \param format format of link file
728 * \param path pathname for link file
729 * \return true on success, false on failure and reports the error
730 */
731static bool
732ro_gui_save_link(const char *url, const char *title, link_format format,
733 char *path)
734{
735 FILE *fp = fopen(path, "w");
736
737 if (!fp) {
738 ro_warn_user("SaveError", strerror(errno));
739 return false;
740 }
741
742 switch (format) {
743 case LINK_ACORN: /* URI */
744 fprintf(fp, "%s\t%s\n", "URI", "100");
745 fprintf(fp, "\t# NetSurf %s\n\n", netsurf_version);
746 fprintf(fp, "\t%s\n", url);
747 if (title)
748 fprintf(fp, "\t%s\n", title);
749 else
750 fprintf(fp, "\t*\n");
751 break;
752 case LINK_ANT: /* URL */
753 case LINK_TEXT: /* Text */
754 fprintf(fp, "%s\n", url);
755 break;
756 }
757
758 fclose(fp);
759
760 switch (format) {
761 case LINK_ACORN: /* URI */
762 xosfile_set_type(path, 0xf91);
763 break;
764 case LINK_ANT: /* URL */
765 xosfile_set_type(path, 0xb28);
766 break;
767 case LINK_TEXT: /* Text */
768 xosfile_set_type(path, 0xfff);
769 break;
770 }
771
772 return true;
773}
774
775
776/**
777 * set RISC OS filetype of file from mimetype
778 *
779 * \param path The path of the file to set filetype on
780 * \param mime_type The mime type to set.
781 */
782static void ro_gui_save_set_file_type(const char *path, lwc_string *mime_type)
783{
784 int rotype = ro_content_filetype_from_mime_type(mime_type);
785 os_error *error;
786
787 error = xosfile_set_type(path, rotype);
788 if (error != NULL) {
789 NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
790 error->errnum, error->errmess);
791 }
792}
793
794
795/**
796 * Prepare an application directory and save_complete() to it.
797 *
798 * \param h content of type CONTENT_HTML to save
799 * \param path path to save as
800 * \return true on success, false on error and error reported
801 */
802static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
803{
804 void *spr = ((byte *) saveas_area) + saveas_area->first;
805 osspriteop_header *sprite = (osspriteop_header *) spr;
806 char name[12];
807 char buf[256];
808 FILE *fp;
809 os_error *error;
810 size_t len;
811 char *dot;
812 int i;
813
814 /* Create dir */
815 error = xosfile_create_dir(path, 0);
816 if (error) {
817 NSLOG(netsurf, INFO, "xosfile_create_dir: 0x%x: %s",
818 error->errnum, error->errmess);
819 ro_warn_user("SaveError", error->errmess);
820 return false;
821 }
822
823 /* Save !Run file */
824 snprintf(buf, sizeof buf, "%s.!Run", path);
825 fp = fopen(buf, "w");
826 if (!fp) {
827 NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
828 ro_warn_user("SaveError", strerror(errno));
829 return false;
830 }
831 fprintf(fp, "IconSprites <Obey$Dir>.!Sprites\n");
832 fprintf(fp, "Filer_Run <Obey$Dir>.index\n");
833 fclose(fp);
834 error = xosfile_set_type(buf, 0xfeb);
835 if (error) {
836 NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
837 error->errnum, error->errmess);
838 ro_warn_user("SaveError", error->errmess);
839 return false;
840 }
841
842 /* create an empty !Runimage so the date gets correctly set */
843 snprintf(buf, sizeof buf, "%s.!RunImage", path);
844 fp = fopen(buf, "w");
845 if (!fp) {
846 NSLOG(netsurf, INFO, "Creating !RunImage failed: errno = %i",
847 errno);
848 } else {
849 fclose(fp);
850 }
851
852 /* Make sure the sprite name matches the directory name, because
853 the user may have renamed the directory since we created the
854 thumbnail sprite */
855
856 dot = strrchr(path, '.');
857 if (dot) dot++; else dot = path;
858 len = strlen(dot);
859 if (len >= 12) len = 12;
860
861 memcpy(name, sprite->name, 12); /* remember original name */
862 memcpy(sprite->name, dot, len);
863 memset(sprite->name + len, 0, 12 - len);
864 for (i = 0; i < 12; i++) /* convert to lower case */
865 if (sprite->name[i] != '\0')
866 sprite->name[i] = tolower(sprite->name[i]);
867
868 /* Create !Sprites */
869 snprintf(buf, sizeof buf, "%s.!Sprites", path);
870
871 error = xosspriteop_save_sprite_file(osspriteop_NAME, saveas_area, buf);
872 if (error) {
873 NSLOG(netsurf, INFO,
874 "xosspriteop_save_sprite_file: 0x%x: %s",
875 error->errnum,
876 error->errmess);
877 ro_warn_user("SaveError", error->errmess);
878 return false;
879 }
880
881 /* restore sprite name in case the save fails and we need to try again */
882 memcpy(sprite->name, name, 12);
883
884 /* save URL file with original URL */
885 snprintf(buf, sizeof buf, "%s.URL", path);
887 content_get_title(h), LINK_ANT, buf))
888 return false;
889
891}
892
893
894/**
895 * Overwrite confirmation callbacks
896 */
898{
901};
902
903
904/**
905 * Save object in native type
906 */
907static bool ro_gui_save_object_native(struct hlcache_handle *h, char *path)
908{
909 int file_type = ro_content_filetype(h);
910
911 if (file_type == osfile_TYPE_SPRITE || file_type == osfile_TYPE_DRAW) {
912 /* Native sprite or drawfile */
913 const uint8_t *source_data;
914 size_t source_size;
915 os_error *error;
916
917 source_data = content_get_source_data(h, &source_size);
918 error = xosfile_save_stamped(path, file_type,
919 (byte *) source_data,
920 (byte *) source_data + source_size);
921 if (error != NULL) {
922 NSLOG(netsurf, INFO,
923 "xosfile_save_stamped: 0x%x: %s",
924 error->errnum,
925 error->errmess);
926 ro_warn_user("SaveError", error->errmess);
927 return false;
928 }
929 } else {
930 /* Non-native type: export */
931 switch (ro_content_native_type(h)) {
932 case osfile_TYPE_SPRITE:
933 {
934 unsigned flags = (os_version == 0xA9) ?
937 }
938 break;
939 case osfile_TYPE_DRAW:
940 /* Must be SVG */
941 return save_as_draw(h, path);
942 default:
943 return false;
944 }
945 }
946
947 return true;
948}
949
950
951/**
952 * Does the actual saving
953 *
954 * \param h handle to content to save (or NULL for other)
955 * \param path path to save to
956 * \param force_overwrite true iff required to overwrite without prompting
957 * \return true on success,
958 * false on (i) error and error reported
959 * or (ii) deferred awaiting user confirmation
960 */
961static bool
962ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
963{
964 os_error *error;
965 const uint8_t *source_data;
966 size_t source_size;
967
968 /* does the user want to check for collisions when saving? */
969 if (!force_overwrite) {
970 fileswitch_object_type obj_type;
971 /* check whether the destination file/dir already exists */
972 error = xosfile_read_stamped(path, &obj_type,
973 NULL, NULL, NULL, NULL, NULL);
974 if (error) {
975 NSLOG(netsurf, INFO, "xosfile_read_stamped: 0x%x:%s",
976 error->errnum, error->errmess);
977 ro_warn_user("SaveError", error->errmess);
978 return false;
979 }
980
981 switch (obj_type) {
982 case osfile_NOT_FOUND:
983 break;
984
985 case osfile_IS_FILE:
986 gui_save_query = query_user("OverwriteFile", NULL, &overwrite_funcs, NULL, messages_get("Replace"), messages_get("DontReplace"));
987// gui_save_query_rsn = QueryRsn_Overwrite;
988 return false;
989
990 default:
991 error = xosfile_make_error(path, obj_type);
992 assert(error);
993 ro_warn_user("SaveError", error->errmess);
994 return false;
995 }
996 }
997
998 switch (gui_save_current_type) {
999#ifdef WITH_DRAW_EXPORT
1000 case GUI_SAVE_DRAW:
1001 return save_as_draw(h, path);
1002#endif
1003#ifdef WITH_PDF_EXPORT
1004 case GUI_SAVE_PDF:
1005 return save_as_pdf(h, path);
1006#endif
1007 case GUI_SAVE_TEXT:
1008 save_as_text(h, path);
1009 xosfile_set_type(path, 0xfff);
1010 break;
1011 case GUI_SAVE_COMPLETE:
1012 assert(h);
1013 if (content_get_type(h) == CONTENT_HTML) {
1014 if (strcmp(path, "<Wimp$Scrap>"))
1015 return ro_gui_save_complete(h, path);
1016
1017 /* we can't send a whole directory to another
1018 * application, so just send the HTML source */
1020 }
1021 else
1022 gui_save_current_type = GUI_SAVE_OBJECT_ORIG; /** \todo do this earlier? */
1024 case GUI_SAVE_SOURCE:
1026 source_data = content_get_source_data(h, &source_size);
1027 error = xosfile_save_stamped(path,
1029 (byte *) source_data,
1030 (byte *) source_data + source_size);
1031 if (error) {
1032 NSLOG(netsurf, INFO,
1033 "xosfile_save_stamped: 0x%x: %s",
1034 error->errnum,
1035 error->errmess);
1036 ro_warn_user("SaveError", error->errmess);
1037 return false;
1038 }
1039 break;
1040
1043
1044 case GUI_SAVE_LINK_URI:
1046 LINK_ACORN, path);
1047
1048 case GUI_SAVE_LINK_URL:
1050 LINK_ANT, path);
1051
1052 case GUI_SAVE_LINK_TEXT:
1054 LINK_TEXT, path);
1055
1057 if (hotlist_export(path, NULL) != NSERROR_OK)
1058 return false;
1059 error = xosfile_set_type(path, 0xfaf);
1060 if (error)
1061 NSLOG(netsurf, INFO,
1062 "xosfile_set_type: 0x%x: %s",
1063 error->errnum,
1064 error->errmess);
1065 break;
1068 return false;
1069 error = xosfile_set_type(path, 0xfaf);
1070 if (error)
1071 NSLOG(netsurf, INFO,
1072 "xosfile_set_type: 0x%x: %s",
1073 error->errnum,
1074 error->errmess);
1075 break;
1076
1078 if (gui_save_selection == NULL)
1079 return false;
1081 free(gui_save_selection);
1082 gui_save_selection = NULL;
1083 return false;
1084 }
1085 free(gui_save_selection);
1086 gui_save_selection = NULL;
1087 xosfile_set_type(path, 0xfff);
1088 break;
1089
1092
1093 default:
1094 NSLOG(netsurf, INFO,
1095 "Unexpected content type: %d, path %s",
1097 path);
1098 return false;
1099 }
1100 return true;
1101}
1102
1103
1104/**
1105 * Handle OK click/keypress in the save dialog.
1106 *
1107 * \param w window handle of save dialog
1108 * \return true on success, false on failure
1109 */
1110bool ro_gui_save_ok(wimp_w w)
1111{
1112 const char *name = ro_gui_get_icon_string(w, ICON_SAVE_PATH);
1113 wimp_pointer pointer;
1114 char path[256];
1115
1116 if (!strrchr(name, '.')) {
1117 ro_warn_user("NoPathError", NULL);
1118 return false;
1119 }
1120
1121 ro_gui_convert_save_path(path, sizeof path, name);
1122 gui_save_sourcew = w;
1123 saving_from_dialog = true;
1124 gui_save_send_dataload = false;
1125 gui_save_close_after = xwimp_get_pointer_info(&pointer)
1126 || !(pointer.buttons & wimp_CLICK_ADJUST);
1127 memcpy(&gui_save_message.data.data_xfer.file_name, path, 1 + strlen(path));
1128
1129 if (ro_gui_save_content(gui_save_content, path, !nsoption_bool(confirm_overwrite))) {
1131 return true;
1132 }
1133 return false;
1134}
1135
1136
1137/**
1138 * Initiates drag saving of an object directly from a browser window
1139 *
1140 * \param g gui window
1141 * \param c content to save
1142 * \param save_type type of save
1143 */
1145 struct hlcache_handle *c,
1146 gui_save_type save_type)
1147{
1148 wimp_pointer pointer;
1149 char icon_buf[20];
1150 os_error *error;
1151
1152 /* Close the save window because otherwise we need two contexts
1153 */
1154 xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
1156
1158 saving_from_dialog = false;
1159
1160 error = xwimp_get_pointer_info(&pointer);
1161 if (error) {
1162 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
1163 error->errnum, error->errmess);
1164 ro_warn_user("WimpError", error->errmess);
1165 return;
1166 }
1167
1170 icon_buf, sizeof(icon_buf));
1171
1172 ro_mouse_drag_start(ro_gui_save_drag_end, NULL, NULL, NULL);
1173
1174 ro_gui_drag_icon(pointer.pos.x, pointer.pos.y, icon_buf);
1175}
1176
1177
1178/**
1179 * Initiates drag saving of a selection from a browser window
1180 *
1181 * \param g gui window
1182 * \param selection selection object
1183 */
1185{
1186 wimp_pointer pointer;
1187 char icon_buf[20];
1188 os_error *error;
1189
1190 /* Close the save window because otherwise we need two contexts
1191 */
1192 xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
1194
1196 saving_from_dialog = false;
1197
1198 error = xwimp_get_pointer_info(&pointer);
1199 if (error) {
1200 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
1201 error->errnum, error->errmess);
1202 ro_warn_user("WimpError", error->errmess);
1203 return;
1204 }
1205
1206
1207 if (gui_save_selection == NULL)
1208 free(gui_save_selection);
1209
1210 if (selection == NULL)
1211 gui_save_selection = strdup("");
1212 else
1213 gui_save_selection = strdup(selection);
1214
1217 icon_buf, sizeof(icon_buf));
1218
1219 ro_mouse_drag_start(ro_gui_save_drag_end, NULL, NULL, NULL);
1220
1221 ro_gui_drag_icon(pointer.pos.x, pointer.pos.y, icon_buf);
1222}
1223
1224
1225/**
1226 * Initiates drag saving of a link/URL file
1227 *
1228 * \param save_type format in which URL should be saved
1229 * \param url url to be saved
1230 * \param title title to be included in URI format, if any
1231 * \param g gui window to save from
1232 * \
1233 */
1235 const char *title, struct gui_window *g)
1236{
1237 wimp_pointer pointer;
1238 char icon_buf[20];
1239 os_error *error;
1240
1241 /* Close the save window because otherwise we need two contexts
1242 */
1243 xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
1245
1249 saving_from_dialog = false;
1250
1251 error = xwimp_get_pointer_info(&pointer);
1252 if (error) {
1253 NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
1254 error->errnum, error->errmess);
1255 ro_warn_user("WimpError", error->errmess);
1256 return;
1257 }
1258
1259 ro_gui_save_set_state(NULL, save_type, url, save_leafname,
1260 LEAFNAME_MAX, icon_buf, sizeof(icon_buf));
1261
1262 ro_mouse_drag_start(ro_gui_save_drag_end, NULL, NULL, NULL);
1263
1264 ro_gui_drag_icon(pointer.pos.x, pointer.pos.y, icon_buf);
1265}
1266
1267
1268/**
1269 * Start drag of icon under the pointer.
1270 *
1271 * \param x The x coordinate of the drag start
1272 * \param y The y coordinate of the drag start
1273 * \param sprite The sprite to use for the drag.
1274 */
1275void ro_gui_drag_icon(int x, int y, const char *sprite)
1276{
1277 os_error *error;
1278 wimp_drag drag;
1279 int r2;
1280
1281 drag.initial.x0 = x - 34;
1282 drag.initial.y0 = y - 34;
1283 drag.initial.x1 = x + 34;
1284 drag.initial.y1 = y + 34;
1285
1286 if (sprite && (xosbyte2(osbyte_READ_CMOS, 28, 0, &r2) || (r2 & 2))) {
1287 osspriteop_area *area = (osspriteop_area*)1;
1288
1289 /* first try our local sprite area in case it's a thumbnail sprite */
1290 if (saveas_area) {
1291 error = xosspriteop_select_sprite(osspriteop_USER_AREA,
1292 saveas_area, (osspriteop_id)sprite, NULL);
1293 if (error) {
1294 if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) {
1295 NSLOG(netsurf, INFO,
1296 "xosspriteop_select_sprite: 0x%x: %s",
1297 error->errnum,
1298 error->errmess);
1299 ro_warn_user("MiscError", error->errmess);
1300 }
1301 }
1302 else
1303 area = saveas_area;
1304 }
1305
1306 error = xdragasprite_start(dragasprite_HPOS_CENTRE |
1307 dragasprite_VPOS_CENTRE |
1308 dragasprite_BOUND_POINTER |
1309 dragasprite_DROP_SHADOW,
1310 area, sprite, &drag.initial, 0);
1311
1312 if (!error) {
1313 using_dragasprite = true;
1314 dragbox_active = true;
1315 return;
1316 }
1317
1318 NSLOG(netsurf, INFO, "xdragasprite_start: 0x%x: %s",
1319 error->errnum, error->errmess);
1320 }
1321
1322 drag.type = wimp_DRAG_USER_FIXED;
1323 drag.bbox.x0 = -0x8000;
1324 drag.bbox.y0 = -0x8000;
1325 drag.bbox.x1 = 0x7fff;
1326 drag.bbox.y1 = 0x7fff;
1327
1328 using_dragasprite = false;
1329 error = xwimp_drag_box(&drag);
1330
1331 if (error) {
1332 NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x: %s",
1333 error->errnum, error->errmess);
1334 ro_warn_user("DragError", error->errmess);
1335 } else {
1336 dragbox_active = true;
1337 }
1338}
1339
1340
1341/**
1342 * Convert a ctrl-char terminated pathname possibly containing spaces
1343 * to a NUL-terminated one containing only hard spaces.
1344 *
1345 * \param dp destination buffer to receive pathname
1346 * \param len size of destination buffer
1347 * \param p source pathname, ctrl-char terminated
1348 */
1349void ro_gui_convert_save_path(char *dp, size_t len, const char *p)
1350{
1351 char *ep = dp + len - 1; /* leave room for NUL */
1352
1353 assert(p <= dp || p > ep); /* in-situ conversion /is/ allowed */
1354
1355 while (dp < ep && *p >= ' ') /* ctrl-char terminated */
1356 {
1357 *dp++ = (*p == ' ') ? 160 : *p;
1358 p++;
1359 }
1360 *dp = '\0';
1361}
1362
1363
1365{
1366 if (dragbox_active) {
1367 os_error *error;
1368 if (using_dragasprite) {
1369 error = xdragasprite_stop();
1370 if (error) {
1371 NSLOG(netsurf, INFO,
1372 "xdragasprite_stop: 0x%x: %s",
1373 error->errnum,
1374 error->errmess);
1375 ro_warn_user("WimpError", error->errmess);
1376 }
1377 }
1378 else {
1379 error = xwimp_drag_box(NULL);
1380 if (error) {
1381 NSLOG(netsurf, INFO,
1382 "xwimp_drag_box: 0x%x: %s",
1383 error->errnum,
1384 error->errmess);
1385 ro_warn_user("WimpError", error->errmess);
1386 }
1387 }
1388 dragbox_active = false;
1389 }
1390}
1391
1392
1393/**
1394 * Send DataSave message on behalf of clipboard code and remember that it's the
1395 * clipboard contents we're being asked for when the DataSaveAck reply arrives
1396 */
1398 wimp_full_message_data_xfer *message, wimp_t to)
1399{
1400 /* Close the save window because otherwise we need two contexts
1401 */
1402
1404
1405 if (ro_message_send_message(wimp_USER_MESSAGE_RECORDED, (wimp_message*)message,
1407 gui_save_current_type = save_type;
1408 gui_save_sourcew = (wimp_w)-1;
1409 saving_from_dialog = false;
1410
1412 }
1413}
1414
1415
1416/**
1417 * Handle Message_DataSaveAck for a drag from the save dialog or browser window,
1418 * or Clipboard protocol.
1419 */
1420void ro_gui_save_datasave_ack(wimp_message *message)
1421{
1422 char *path = message->data.data_xfer.file_name;
1423 struct hlcache_handle *h = gui_save_content;
1424 bool force_overwrite;
1425
1426 switch (gui_save_current_type) {
1427 case GUI_SAVE_LINK_URI:
1428 case GUI_SAVE_LINK_URL:
1429 case GUI_SAVE_LINK_TEXT:
1434 break;
1435
1436 default:
1437 if (!gui_save_content) {
1438 NSLOG(netsurf, INFO,
1439 "unexpected DataSaveAck: gui_save_content not set");
1440 return;
1441 }
1442 break;
1443 }
1444
1447 path, true);
1448
1450 memcpy(&gui_save_message, message, sizeof(gui_save_message));
1451
1452 /* if saving/pasting to another application, don't request user
1453 confirmation; a ScrapFile almost certainly exists already */
1454 if (message->data.data_xfer.est_size == -1)
1455 force_overwrite = true;
1456 else
1457 force_overwrite = !nsoption_bool(confirm_overwrite);
1458
1459 if (ro_gui_save_content(h, path, force_overwrite))
1461}
void die(const char *error)
Cause an abnormal program termination.
Definition: misc.c:69
Browser window creation and manipulation interface.
bool browser_window_drop_file_at_point(struct browser_window *bw, int x, int y, char *file)
Drop a file onto a browser window at a particular point, or determine if a file may be dropped onto t...
@ CONTENT_HTML
content is HTML
Definition: content_type.h:58
nserror global_history_export(const char *path, const char *title)
Save global history to file (html)
nserror hotlist_export(const char *path, const char *title)
Save hotlist to file.
Definition: hotlist.c:1086
wimp_w dialog_saveas
Definition: dialog.c:75
wimp_window * ro_gui_dialog_load_template(const char *template_name)
Load a template without creating a window.
Definition: dialog.c:242
void ro_gui_dialog_close(wimp_w close)
Close a dialog box.
Definition: dialog.c:335
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_BAD_ENCODING
The character set is unknown.
Definition: errors.h:45
@ NSERROR_OK
No error.
Definition: errors.h:30
Form handling public interface.
nserror utf8_to_local_encoding(const char *string, size_t len, char **result)
Definition: utf8.c:89
osspriteop_area * riscos_bitmap_convert_8bpp(struct bitmap *bitmap)
Convert a bitmap to 8bpp.
Definition: bitmap.c:633
void riscos_bitmap_destroy(void *vbitmap)
Free a bitmap.
Definition: bitmap.c:202
bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
Save a bitmap in the platform's native format.
Definition: bitmap.c:218
void * riscos_bitmap_create(int width, int height, enum gui_bitmap_flags flags)
Create a bitmap.
Definition: bitmap.c:125
nserror riscos_bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
Render content into bitmap.
Definition: bitmap.c:724
#define BITMAP_SAVE_FULL_ALPHA
save with full alpha channel (if not opaque)
Definition: bitmap.h:33
void ro_mouse_drag_start(void(*drag_end)(wimp_dragged *dragged, void *data), void(*drag_track)(wimp_pointer *pointer, void *data), void(*drag_cancel)(void *data), void *data)
Start a drag, providing a function to be called when the Wimp_DragEnd event is received and optionall...
Definition: mouse.c:115
Mouse dragging and tracking support interface for RISC OS.
bool ro_gui_save_clipboard(const char *path)
Save the clipboard contents to a file.
Text selection import/export (interface).
Browser window handling (interface).
const char *const netsurf_version
User friendly version string.
Definition: gui_menu.c:92
Generic bitmap handling interface.
@ BITMAP_CLEAR
memory should be wiped to 0
Definition: bitmap.h:39
@ BITMAP_OPAQUE
image is opaque
Definition: bitmap.h:38
Public content interface.
struct nsurl * hlcache_handle_get_url(const struct hlcache_handle *handle)
Retrieve the URL associated with a high level cache handle.
const char * content_get_title(struct hlcache_handle *h)
Retrieve title associated with content.
Definition: content.c:1106
struct bitmap * content_get_bitmap(struct hlcache_handle *h)
Retrieve the bitmap contained in an image content.
Definition: content.c:1264
const uint8_t * content_get_source_data(struct hlcache_handle *h, size_t *size)
Retrieve source of content.
Definition: content.c:1209
content_type content_get_type(struct hlcache_handle *h)
Retrieve computed type of content.
Definition: content.c:1061
Interface to platform-specific graphical user interface window operations.
gui_save_type
Definition: window.h:39
@ GUI_SAVE_OBJECT_ORIG
Definition: window.h:45
@ GUI_SAVE_DRAW
Definition: window.h:41
@ GUI_SAVE_HISTORY_EXPORT_HTML
Definition: window.h:51
@ GUI_SAVE_TEXT
Definition: window.h:43
@ GUI_SAVE_CLIPBOARD_CONTENTS
Definition: window.h:53
@ GUI_SAVE_SOURCE
Definition: window.h:40
@ GUI_SAVE_HOTLIST_EXPORT_HTML
Definition: window.h:50
@ GUI_SAVE_LINK_TEXT
Definition: window.h:49
@ GUI_SAVE_LINK_URI
Definition: window.h:47
@ GUI_SAVE_TEXT_SELECTION
Definition: window.h:52
@ GUI_SAVE_OBJECT_NATIVE
Definition: window.h:46
@ GUI_SAVE_LINK_URL
Definition: window.h:48
@ GUI_SAVE_COMPLETE
Definition: window.h:44
@ GUI_SAVE_PDF
Definition: window.h:42
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
bool ro_message_send_message(wimp_event_no event, wimp_message *message, wimp_t task, void(*callback)(wimp_message *message))
Sends a message and registers a return route for a bounce.
Definition: message.c:57
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)
Sends a message and registers a return route for a bounce.
Definition: message.c:94
Automated RISC OS message routing (interface).
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
NetSurf URL handling (interface).
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
Attempt to find a nice filename for a URL.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
query_id query_user(const char *query, const char *detail, const query_callback *cb, void *pw, const char *yes, const char *no)
Display a query to the user, requesting a response, near the current pointer position to keep the req...
Definition: query.c:112
query_response
Definition: query.h:25
int query_id
Definition: query.h:32
int ro_content_filetype_from_mime_type(lwc_string *mime_type)
Determine the RISC OS filetype for a MIME type.
Definition: filetype.c:288
int ro_content_filetype(struct hlcache_handle *c)
Determine the RISC OS filetype for a content.
Definition: filetype.c:243
int ro_content_native_type(struct hlcache_handle *c)
Determine the native RISC OS filetype to export a content as.
Definition: filetype.c:263
RISC OS filetpe interface.
ro_gui_drag_type gui_current_drag_type
Definition: gui.c:114
nserror ro_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.c:2076
int os_version
Definition: gui.c:96
#define ICON_SAVE_ICON
Definition: gui.h:179
@ GUI_DRAG_SAVE
Definition: gui.h:69
@ GUI_DRAG_NONE
Definition: gui.h:69
#define ICON_SAVE_PATH
Definition: gui.h:180
File/object/selection saving (Interface).
bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, os_coord *pos)
Convert x,y screen co-ordinates into window co-ordinates.
Definition: window.c:4855
struct gui_window * ro_gui_window_lookup(wimp_w window)
Convert a RISC OS window handle to a gui_window.
Definition: window.c:4823
static void ro_gui_save_drag_end(wimp_dragged *drag, void *data)
Handle User_Drag_Box event for a drag from the save dialog or browser window.
Definition: save.c:501
void gui_drag_save_selection(struct gui_window *g, const char *selection)
Initiates drag saving of a selection from a browser window.
Definition: save.c:1184
static const struct gui_save_table_entry gui_save_table[]
Table of filetypes and default filenames.
Definition: save.c:125
static void ro_gui_save_set_state(struct hlcache_handle *h, gui_save_type save_type, const nsurl *url, char *leaf_buf, size_t leaf_len, char *icon_buf, size_t icon_len)
Suggest a leafname and sprite name for the given content.
Definition: save.c:295
static char * gui_save_selection
Definition: save.c:91
static bool saving_from_dialog
Definition: save.c:102
static bool dragbox_active
Definition: save.c:100
#define LEAFNAME_MAX
Definition: save.c:105
void ro_gui_send_datasave(gui_save_type save_type, wimp_full_message_data_xfer *message, wimp_t to)
Send DataSave message on behalf of clipboard code and remember that it's the clipboard contents we're...
Definition: save.c:1397
void ro_gui_drag_icon(int x, int y, const char *sprite)
Start drag of icon under the pointer.
Definition: save.c:1275
static bool ro_gui_save_link(const char *url, const char *title, link_format format, char *path)
Save a link file.
Definition: save.c:732
static void ro_gui_save_done(void)
Save completed, inform recipient and close our 'save as' dialog.
Definition: save.c:630
void ro_gui_drag_save_link(gui_save_type save_type, const nsurl *url, const char *title, struct gui_window *g)
Initiates drag saving of a link/URL file.
Definition: save.c:1234
static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
Prepare an application directory and save_complete() to it.
Definition: save.c:802
static osspriteop_area * saveas_area
Definition: save.c:103
void gui_drag_save_object(struct gui_window *g, struct hlcache_handle *c, gui_save_type save_type)
Initiates drag saving of an object directly from a browser window.
Definition: save.c:1144
static wimp_w gui_save_sourcew
Definition: save.c:104
static const char * gui_save_url
Definition: save.c:92
static char save_leafname[LEAFNAME_MAX]
Definition: save.c:106
static const query_callback overwrite_funcs
Overwrite confirmation callbacks.
Definition: save.c:897
static size_t save_dir_len
Definition: save.c:110
static bool ro_gui_save_object_native(struct hlcache_handle *h, char *path)
Save object in native type.
Definition: save.c:907
link_format
Definition: save.c:112
@ LINK_ACORN
Definition: save.c:112
@ LINK_ANT
Definition: save.c:112
@ LINK_TEXT
Definition: save.c:112
static query_id gui_save_query
Definition: save.c:95
static bool using_dragasprite
in-progress Wimp_DragBox/DragASprite op
Definition: save.c:101
void ro_gui_drag_box_cancel(void)
Definition: save.c:1364
void ro_gui_convert_save_path(char *dp, size_t len, const char *p)
Convert a ctrl-char terminated pathname possibly containing spaces to a NUL-terminated one containing...
Definition: save.c:1349
void ro_gui_saveas_quit(void)
Clean-up function that releases our sprite area and memory.
Definition: save.c:216
bool ro_gui_save_ok(wimp_w w)
Handle OK click/keypress in the save dialog.
Definition: save.c:1110
static wimp_message gui_save_message
Definition: save.c:97
void ro_gui_save_datasave_ack(wimp_message *message)
Handle Message_DataSaveAck for a drag from the save dialog or browser window, or Clipboard protocol.
Definition: save.c:1420
static void ro_gui_save_overwrite_confirmed(query_id id, enum query_response res, void *p)
Overwrite of existing file confirmed, proceed with the save.
Definition: save.c:714
void ro_gui_save_prepare(gui_save_type save_type, struct hlcache_handle *h, char *s, const nsurl *url, const char *title)
Prepares the save box to reflect gui_save_type and a content, and opens it.
Definition: save.c:437
static int gui_save_filetype
Definition: save.c:94
static gui_save_type gui_save_current_type
Definition: save.c:89
static void ro_gui_save_bounced(wimp_message *message)
Handle lack of Message_DataSaveAck for drags, saveas dialogs and clipboard code.
Definition: save.c:489
static bool ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
Does the actual saving.
Definition: save.c:962
wimp_w ro_gui_saveas_create(const char *template_name)
Create the saveas dialogue from the given template, and the sprite area necessary for our thumbnail (...
Definition: save.c:152
static bool ro_gui_save_create_thumbnail(struct hlcache_handle *h, const char *name)
Create a thumbnail sprite for the page being saved.
Definition: save.c:241
static bool gui_save_send_dataload
Definition: save.c:96
static void ro_gui_save_set_file_type(const char *path, lwc_string *mime_type)
set RISC OS filetype of file from mimetype
Definition: save.c:782
static bool gui_save_close_after
Definition: save.c:98
static const char * gui_save_title
Definition: save.c:93
static char * save_dir
Current save directory (updated by and used for dialog-based saving)
Definition: save.c:109
static struct hlcache_handle * gui_save_content
Definition: save.c:90
static void ro_gui_save_overwrite_cancelled(query_id id, enum query_response res, void *p)
User has opted not to overwrite the existing file.
Definition: save.c:701
void ro_gui_save_start_drag(wimp_pointer *pointer)
Starts a drag for the save dialog.
Definition: save.c:602
nserror save_complete(hlcache_handle *c, const char *path, save_complete_set_type_cb set_type)
Save an HTML page with all dependencies.
Save HTML document with dependencies (interface).
void save_as_text(struct hlcache_handle *c, char *path)
Extract the text from an HTML content and save it as a text file.
Definition: save_text.c:57
Text export of HTML (interface).
Interface to utility string handling.
RISC OS wimp toolkit bitmap.
Definition: bitmap.c:68
char * title
Definition: bitmap.c:83
struct nsurl * url
Definition: bitmap.c:82
int x
Window dimensions.
An entry in gui_save_table.
Definition: save.c:115
int filetype
Definition: save.c:116
const char * name
Definition: save.c:117
first entry in window list
Definition: gui.c:296
char * url
Definition: gui.h:154
struct fbtk_widget_s * window
Definition: gui.h:33
char * title
Definition: gui.h:153
struct browser_window * bw
The 'content' window that is rendered in the gui_window.
Definition: gui.c:314
High-level cache handle.
Definition: hlcache.c:66
UCS conversion tables (interface) This is only used if nothing claims Service_International,...
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:270
bool utf8_save_text(const char *utf8_text, const char *path)
Save the given utf8 text to a file, converting to local encoding.
Definition: utf8.c:467
char to[32]
Encoding name to convert to.
Definition: utf8.c:144
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
Definition: utils.h:115
#define min(x, y)
Definition: utils.h:46
Version information interface.
os_error * ro_gui_wimp_get_sprite(const char *name, osspriteop_header **sprite)
Locate a sprite in the Wimp sprite pool, returning a pointer to it.
Definition: wimp.c:896
void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
Set the contents of a text or sprite icon to a string.
Definition: wimp.c:269
const char * ro_gui_get_icon_string(wimp_w w, wimp_i i)
Read the contents of a text or sprite icon.
Definition: wimp.c:235
void ro_gui_set_icon_sprite(wimp_w w, wimp_i i, osspriteop_area *area, const char *name)
Set an icon's sprite.
Definition: wimp.c:638
General RISC OS WIMP/OS library functions (interface).
bool ro_gui_wimp_event_memorise(wimp_w w)
Memorises the current state of any registered components in a window.
Definition: wimp_event.c:139
Automated RISC OS WIMP event handling (interface).
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
static nserror bitmap(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, colour bg, bitmap_flags_t flags)
Plot a bitmap.
Definition: plot.c:857