summaryrefslogtreecommitdiff
path: root/frontends/riscos
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-05-05 22:28:51 +0100
committerVincent Sanders <vince@kyllikki.org>2016-05-15 13:44:34 +0100
commitd21447d096a320a08b3efb2b8768fad0dcdcfd64 (patch)
tree1a83814b7c9e94b2f13c473261f23dd3a17dee64 /frontends/riscos
parent2cbb337756d9af5bda4d594964d446439f602551 (diff)
downloadnetsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.gz
netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.bz2
move frontends into sub directory
Diffstat (limited to 'frontends/riscos')
-rw-r--r--frontends/riscos/401login.c236
-rw-r--r--frontends/riscos/Makefile153
-rw-r--r--frontends/riscos/Makefile.defaults37
-rw-r--r--frontends/riscos/assert.c44
-rw-r--r--frontends/riscos/bitmap.c876
-rw-r--r--frontends/riscos/bitmap.h116
-rw-r--r--frontends/riscos/buffer.c396
-rw-r--r--frontends/riscos/buffer.h31
-rw-r--r--frontends/riscos/configure.c410
-rw-r--r--frontends/riscos/configure.h34
-rw-r--r--frontends/riscos/configure/con_cache.c107
-rw-r--r--frontends/riscos/configure/con_connect.c220
-rw-r--r--frontends/riscos/configure/con_content.c107
-rw-r--r--frontends/riscos/configure/con_fonts.c209
-rw-r--r--frontends/riscos/configure/con_home.c118
-rw-r--r--frontends/riscos/configure/con_image.c269
-rw-r--r--frontends/riscos/configure/con_inter.c145
-rw-r--r--frontends/riscos/configure/con_language.c139
-rw-r--r--frontends/riscos/configure/con_secure.c83
-rw-r--r--frontends/riscos/configure/con_theme.c420
-rw-r--r--frontends/riscos/configure/configure.h43
-rw-r--r--frontends/riscos/content-handlers/artworks.c435
-rw-r--r--frontends/riscos/content-handlers/artworks.h42
-rw-r--r--frontends/riscos/content-handlers/awrender.s390
-rw-r--r--frontends/riscos/content-handlers/draw.c254
-rw-r--r--frontends/riscos/content-handlers/draw.h42
-rw-r--r--frontends/riscos/content-handlers/sprite.c266
-rw-r--r--frontends/riscos/content-handlers/sprite.h44
-rw-r--r--frontends/riscos/cookies.c385
-rw-r--r--frontends/riscos/cookies.h38
-rw-r--r--frontends/riscos/dialog.c816
-rw-r--r--frontends/riscos/dialog.h55
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!Boot,feb17
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!Help,feb2
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!Run,feb9
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!RunImage,ffbbin0 -> 2985 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites,ff9bin0 -> 864 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites22,ff9bin0 -> 2504 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Caches/Blank1
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/MultiError,ffbbin0 -> 24031 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/ResFind,ffbbin0 -> 1930 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/!Meta9
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Help60
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Messages8
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Templates,fecbin0 -> 541 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Boot,feb5
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Help1
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Run,feb5
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites,ff9bin0 -> 5780 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites11,ff9bin0 -> 11132 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites22,ff9bin0 -> 7324 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Acorn/Latin1bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/CentEurobin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Cyrillicbin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Romanbin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Ukrainianbin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/BigFivebin0 -> 29516 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C0/40[ISO646]bin0 -> 64 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C1/43[IS6429]bin0 -> 64 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/40[646old]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/41[646-GB]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/42[646IRV]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/43[FinSwe]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/47[646-SE]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/48[646-SE]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/49[JS201K]1
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4A[JS201R]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4B[646-DE]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4C[646-PT]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/54[GB1988]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/56[Teltxt]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/59[646-IT]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/5A[646-ES]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/60[646-NO]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/66[646-FR]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/69[646-HU]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6B[Arabic]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6C[IS6937]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/7A[SerbCr]bin0 -> 188 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/40[JS6226]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/41[GB2312]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/42[JIS208]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/43[KS1001]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/44[JIS212]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/47[CNS1]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/48[CNS2]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/49[CNS3]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4A[CNS4]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4B[CNS5]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4C[CNS6]bin0 -> 17672 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4D[CNS7]2
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/41[Lat1]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/42[Lat2]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/43[Lat3]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/44[Lat4]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/46[Greek]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/47[Arabic]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/48[Hebrew]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4C[Cyrill]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4D[Lat5]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/50[LatSup]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/52[IS6937]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/54[Thai]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/56[Lat6]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/58[L6Sami]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/59[Lat7]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5C[Welsh]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5D[Sami]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5E[Hebrew]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5F[Lat8]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/62[Lat9]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/66[Lat10]bin0 -> 192 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/KOI8-Rbin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1250bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1251bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1252bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1253bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1254bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1256bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP866bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP874bin0 -> 256 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP932bin0 -> 996 bytes
-rw-r--r--frontends/riscos/distribution/!Boot/Resources/!Unicode/Files/Aliases303
-rw-r--r--frontends/riscos/distribution/!System/310/Modules/CryptRand,ffabin0 -> 15584 bytes
-rw-r--r--frontends/riscos/distribution/!System/310/Modules/Iconv,ffabin0 -> 66240 bytes
-rw-r--r--frontends/riscos/distribution/!System/310/Modules/Network/URI,ffabin0 -> 9188 bytes
-rwxr-xr-xfrontends/riscos/distribution/!System/310/Modules/SharedULib,ffabin0 -> 3116 bytes
-rw-r--r--frontends/riscos/distribution/!System/310/Modules/Tinct,ffabin0 -> 25680 bytes
-rw-r--r--frontends/riscos/distribution/3rdParty/AcornURI/!ReadMe34
-rw-r--r--frontends/riscos/distribution/3rdParty/AcornURI/Copying504
-rw-r--r--frontends/riscos/distribution/3rdParty/CryptRand/Copyright46
-rw-r--r--frontends/riscos/distribution/3rdParty/Iconv/ReadMe45
-rw-r--r--frontends/riscos/distribution/3rdParty/Iconv/doc/API132
-rw-r--r--frontends/riscos/distribution/3rdParty/Iconv/doc/ChangeLog114
-rw-r--r--frontends/riscos/distribution/3rdParty/Iconv/doc/Uni-iconv204
-rw-r--r--frontends/riscos/distribution/3rdParty/SharedULib/Copyright761
-rw-r--r--frontends/riscos/distribution/3rdParty/Tinct/!Help304
-rw-r--r--frontends/riscos/distribution/LeesMij73
-rw-r--r--frontends/riscos/distribution/ReadMe61
-rw-r--r--frontends/riscos/download.c1629
-rw-r--r--frontends/riscos/filetype.c352
-rw-r--r--frontends/riscos/filetype.h128
-rw-r--r--frontends/riscos/font.c598
-rw-r--r--frontends/riscos/font.h45
-rw-r--r--frontends/riscos/global_history.c413
-rw-r--r--frontends/riscos/global_history.h38
-rw-r--r--frontends/riscos/gui.c2522
-rw-r--r--frontends/riscos/gui.h271
-rw-r--r--frontends/riscos/gui/button_bar.c1229
-rw-r--r--frontends/riscos/gui/button_bar.h309
-rw-r--r--frontends/riscos/gui/progress_bar.c535
-rw-r--r--frontends/riscos/gui/progress_bar.h44
-rw-r--r--frontends/riscos/gui/status_bar.c625
-rw-r--r--frontends/riscos/gui/status_bar.h45
-rw-r--r--frontends/riscos/gui/throbber.c418
-rw-r--r--frontends/riscos/gui/throbber.h147
-rw-r--r--frontends/riscos/gui/url_bar.c1344
-rw-r--r--frontends/riscos/gui/url_bar.h329
-rw-r--r--frontends/riscos/help.c361
-rw-r--r--frontends/riscos/help.h33
-rw-r--r--frontends/riscos/history.c336
-rw-r--r--frontends/riscos/hotlist.c737
-rw-r--r--frontends/riscos/hotlist.h53
-rw-r--r--frontends/riscos/iconbar.c261
-rw-r--r--frontends/riscos/iconbar.h32
-rw-r--r--frontends/riscos/image.c219
-rw-r--r--frontends/riscos/image.h39
-rw-r--r--frontends/riscos/menus.c958
-rw-r--r--frontends/riscos/menus.h183
-rw-r--r--frontends/riscos/message.c247
-rw-r--r--frontends/riscos/message.h42
-rw-r--r--frontends/riscos/mouse.c282
-rw-r--r--frontends/riscos/mouse.h110
-rw-r--r--frontends/riscos/options.h68
-rw-r--r--frontends/riscos/oslib_pre7.h42
-rw-r--r--frontends/riscos/palettes.c321
-rw-r--r--frontends/riscos/palettes.h33
-rw-r--r--frontends/riscos/plotters.c525
-rw-r--r--frontends/riscos/print.c976
-rw-r--r--frontends/riscos/print.h33
-rw-r--r--frontends/riscos/query.c381
-rw-r--r--frontends/riscos/query.h53
-rw-r--r--frontends/riscos/save.c1401
-rw-r--r--frontends/riscos/save.h50
-rw-r--r--frontends/riscos/save_draw.c474
-rw-r--r--frontends/riscos/save_draw.h31
-rw-r--r--frontends/riscos/save_pdf.c60
-rw-r--r--frontends/riscos/save_pdf.h31
-rw-r--r--frontends/riscos/schedule.c163
-rw-r--r--frontends/riscos/scripts/Help12
-rw-r--r--frontends/riscos/scripts/Run109
-rw-r--r--frontends/riscos/search.c475
-rw-r--r--frontends/riscos/searchweb.c18
-rw-r--r--frontends/riscos/sslcert.c348
-rw-r--r--frontends/riscos/sslcert.h34
-rw-r--r--frontends/riscos/templates/de3845
-rw-r--r--frontends/riscos/templates/en3837
-rw-r--r--frontends/riscos/templates/fr3862
-rw-r--r--frontends/riscos/templates/nl3887
-rw-r--r--frontends/riscos/textarea.c1160
-rw-r--r--frontends/riscos/textarea.h50
-rw-r--r--frontends/riscos/textselection.c657
-rw-r--r--frontends/riscos/textselection.h53
-rw-r--r--frontends/riscos/theme.c741
-rw-r--r--frontends/riscos/theme.h109
-rw-r--r--frontends/riscos/theme_install.c237
-rw-r--r--frontends/riscos/tinct.h154
-rw-r--r--frontends/riscos/toolbar.c1788
-rw-r--r--frontends/riscos/toolbar.h542
-rw-r--r--frontends/riscos/treeview.c1279
-rw-r--r--frontends/riscos/treeview.h55
-rw-r--r--frontends/riscos/ucstables.c697
-rw-r--r--frontends/riscos/ucstables.h29
-rw-r--r--frontends/riscos/uri.c139
-rw-r--r--frontends/riscos/uri.h30
-rw-r--r--frontends/riscos/url_complete.c740
-rw-r--r--frontends/riscos/url_complete.h100
-rw-r--r--frontends/riscos/url_protocol.c226
-rw-r--r--frontends/riscos/url_protocol.h35
-rw-r--r--frontends/riscos/url_suggest.c239
-rw-r--r--frontends/riscos/url_suggest.h38
-rw-r--r--frontends/riscos/wimp.c1134
-rw-r--r--frontends/riscos/wimp.h83
-rw-r--r--frontends/riscos/wimp_event.c1814
-rw-r--r--frontends/riscos/wimp_event.h116
-rw-r--r--frontends/riscos/wimputils.h65
-rw-r--r--frontends/riscos/window.c5025
-rw-r--r--frontends/riscos/window.h46
228 files changed, 63025 insertions, 0 deletions
diff --git a/frontends/riscos/401login.c b/frontends/riscos/401login.c
new file mode 100644
index 000000000..e95a74809
--- /dev/null
+++ b/frontends/riscos/401login.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <oslib/wimp.h>
+
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+
+#include "riscos/gui.h"
+#include "riscos/dialog.h"
+#include "riscos/wimp_event.h"
+
+#define ICON_401LOGIN_LOGIN 0
+#define ICON_401LOGIN_CANCEL 1
+#define ICON_401LOGIN_HOST 2
+#define ICON_401LOGIN_REALM 3
+#define ICON_401LOGIN_USERNAME 4
+#define ICON_401LOGIN_PASSWORD 5
+
+static void ro_gui_401login_close(wimp_w w);
+static bool ro_gui_401login_apply(wimp_w w);
+static void ro_gui_401login_open(nsurl *url, lwc_string *host,
+ const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+static wimp_window *dialog_401_template;
+
+struct session_401 {
+ lwc_string *host; /**< Host for user display */
+ char *realm; /**< Authentication realm */
+ char uname[256]; /**< Buffer for username */
+ nsurl *url; /**< URL being fetched */
+ char pwd[256]; /**< Buffer for password */
+ nserror (*cb)(bool proceed, void *pw); /**< Continuation callback */
+ void *cbpw; /**< Continuation callback data */
+};
+
+
+/**
+ * Load the 401 login window template.
+ */
+
+void ro_gui_401login_init(void)
+{
+ dialog_401_template = ro_gui_dialog_load_template("login");
+}
+
+
+/**
+ * Open the login dialog
+ */
+void gui_401login_open(nsurl *url, const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw)
+{
+ lwc_string *host = nsurl_get_component(url, NSURL_HOST);
+ assert(host != NULL);
+
+ ro_gui_401login_open(url, host, realm, cb, cbpw);
+
+ lwc_string_unref(host);
+}
+
+
+/**
+ * Open a 401 login window.
+ */
+
+void ro_gui_401login_open(nsurl *url, lwc_string *host, const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw)
+{
+ struct session_401 *session;
+ wimp_w w;
+ const char *auth;
+
+ session = calloc(1, sizeof(struct session_401));
+ if (!session) {
+ ro_warn_user("NoMemory", 0);
+ return;
+ }
+
+ session->url = nsurl_ref(url);
+ if (realm == NULL)
+ realm = "Secure Area";
+ auth = urldb_get_auth_details(session->url, realm);
+ if (auth == NULL) {
+ session->uname[0] = '\0';
+ session->pwd[0] = '\0';
+ } else {
+ const char *pwd;
+ size_t pwd_len;
+
+ pwd = strchr(auth, ':');
+ assert(pwd && pwd < auth + sizeof(session->uname));
+ memcpy(session->uname, auth, pwd - auth);
+ session->uname[pwd - auth] = '\0';
+ ++pwd;
+ pwd_len = strlen(pwd);
+ assert(pwd_len < sizeof(session->pwd));
+ memcpy(session->pwd, pwd, pwd_len);
+ session->pwd[pwd_len] = '\0';
+ }
+ session->host = lwc_string_ref(host);
+ session->realm = strdup(realm);
+ session->cb = cb;
+ session->cbpw = cbpw;
+
+ if (!session->realm) {
+ nsurl_unref(session->url);
+ lwc_string_unref(session->host);
+ free(session);
+ ro_warn_user("NoMemory", 0);
+ return;
+ }
+
+ /* fill in download window icons */
+ dialog_401_template->icons[ICON_401LOGIN_HOST].data.
+ indirected_text.text =
+ (char *)lwc_string_data(session->host);
+ dialog_401_template->icons[ICON_401LOGIN_HOST].data.
+ indirected_text.size =
+ lwc_string_length(session->host) + 1;
+ dialog_401_template->icons[ICON_401LOGIN_REALM].data.
+ indirected_text.text = session->realm;
+ dialog_401_template->icons[ICON_401LOGIN_REALM].data.
+ indirected_text.size = strlen(session->realm) + 1;
+ dialog_401_template->icons[ICON_401LOGIN_USERNAME].data.
+ indirected_text.text = session->uname;
+ dialog_401_template->icons[ICON_401LOGIN_USERNAME].data.
+ indirected_text.size = sizeof(session->uname);
+ dialog_401_template->icons[ICON_401LOGIN_PASSWORD].data.
+ indirected_text.text = session->pwd;
+ dialog_401_template->icons[ICON_401LOGIN_PASSWORD].data.
+ indirected_text.size = sizeof(session->pwd);
+
+ /* create and open the window */
+ w = wimp_create_window(dialog_401_template);
+
+ ro_gui_wimp_event_register_text_field(w, ICON_401LOGIN_USERNAME);
+ ro_gui_wimp_event_register_text_field(w, ICON_401LOGIN_PASSWORD);
+ ro_gui_wimp_event_register_cancel(w, ICON_401LOGIN_CANCEL);
+ ro_gui_wimp_event_register_ok(w, ICON_401LOGIN_LOGIN,
+ ro_gui_401login_apply);
+ ro_gui_wimp_event_register_close_window(w, ro_gui_401login_close);
+ ro_gui_wimp_event_set_user_data(w, session);
+
+ ro_gui_dialog_open_persistent(NULL, w, false);
+}
+
+/**
+ * Handle closing of login dialog
+ */
+void ro_gui_401login_close(wimp_w w)
+{
+ os_error *error;
+ struct session_401 *session;
+
+ session = (struct session_401 *)ro_gui_wimp_event_get_user_data(w);
+
+ assert(session);
+
+ /* If ok didn't happen, send failure response */
+ if (session->cb != NULL)
+ session->cb(false, session->cbpw);
+
+ nsurl_unref(session->url);
+ lwc_string_unref(session->host);
+ free(session->realm);
+ free(session);
+
+ error = xwimp_delete_window(w);
+ if (error) {
+ LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ ro_gui_wimp_event_finalise(w);
+}
+
+
+/* Login Clicked -> create a new fetch request, specifying uname & pwd
+ * CURLOPT_USERPWD takes a string "username:password"
+ */
+bool ro_gui_401login_apply(wimp_w w)
+{
+ struct session_401 *session;
+ char *auth;
+
+ session = (struct session_401 *)ro_gui_wimp_event_get_user_data(w);
+
+ assert(session);
+
+ auth = malloc(strlen(session->uname) + strlen(session->pwd) + 2);
+ if (!auth) {
+ LOG("calloc failed");
+ ro_warn_user("NoMemory", 0);
+ return false;
+ }
+
+ sprintf(auth, "%s:%s", session->uname, session->pwd);
+
+ urldb_set_auth_details(session->url, session->realm, auth);
+
+ free(auth);
+
+ session->cb(true, session->cbpw);
+
+ /* Flag that we sent response by invalidating callback details */
+ session->cb = NULL;
+ session->cbpw = NULL;
+
+ return true;
+}
+
diff --git a/frontends/riscos/Makefile b/frontends/riscos/Makefile
new file mode 100644
index 000000000..6ed076800
--- /dev/null
+++ b/frontends/riscos/Makefile
@@ -0,0 +1,153 @@
+#
+# Makefile for NetSurf RISC OS target
+#
+# This file is part of NetSurf
+
+# ----------------------------------------------------------------------------
+# RISC OS target setup
+# ----------------------------------------------------------------------------
+
+$(eval $(call pkg_config_find_and_add,libcares,Cares))
+
+$(eval $(call feature_enabled,DRAW,-DWITH_DRAW,,Drawfile rendering))
+$(eval $(call feature_enabled,SPRITE,-DWITH_SPRITE,,Sprite rendering))
+$(eval $(call feature_enabled,ARTWORKS,-DWITH_ARTWORKS,,ArtWorks rendering))
+$(eval $(call feature_enabled,DRAW_EXPORT,-DWITH_DRAW_EXPORT,-lpencil,Drawfile export))
+
+
+TPD_RISCOS = $(foreach TPL,$(notdir $(TPL_RISCOS)), \
+ !NetSurf/Resources/$(TPL)/Templates$(TPLEXT))
+
+RESOURCES = $(TPD_RISCOS)
+
+CFLAGS += -Driscos -std=c99 -D_BSD_SOURCE -D_POSIX_C_SOURCE \
+ -mpoke-function-name -fno-strict-aliasing
+
+CFLAGS += -I$(GCCSDK_INSTALL_ENV)/include
+ifeq ($(HOST),riscos)
+ CFLAGS += -I<OSLib$$Dir> -mthrowback
+endif
+ASFLAGS += -xassembler-with-cpp -I. -I$(GCCSDK_INSTALL_ENV)/include
+LDFLAGS += -L$(GCCSDK_INSTALL_ENV)/lib -lrufl
+ifeq ($(HOST),riscos)
+ LDFLAGS += -LOSLib: -lOSLib32
+else
+ LDFLAGS += -lOSLib32
+ ifeq ($(SUBTARGET),-elf)
+ # Go for static builds & AIF binary at the moment:
+ CFLAGS += -static
+ LDFLAGS += -static
+ EXEEXT := ,ff8
+ endif
+endif
+
+# ----------------------------------------------------------------------------
+# Source file setup
+# ----------------------------------------------------------------------------
+
+# S_RISCOS are sources purely for the RISC OS build
+S_FRONTEND := 401login.c assert.c bitmap.c buffer.c cookies.c configure.c \
+ dialog.c download.c filetype.c font.c \
+ global_history.c gui.c help.c history.c hotlist.c iconbar.c \
+ image.c menus.c message.c mouse.c palettes.c plotters.c \
+ print.c query.c save.c save_draw.c save_pdf.c schedule.c \
+ search.c searchweb.c sslcert.c textarea.c \
+ textselection.c theme.c theme_install.c toolbar.c \
+ treeview.c ucstables.c uri.c url_complete.c url_protocol.c \
+ url_suggest.c wimp.c wimp_event.c window.c \
+ $(addprefix content-handlers/,artworks.c awrender.s draw.c \
+ sprite.c) \
+ $(addprefix gui/,button_bar.c progress_bar.c status_bar.c \
+ throbber.c url_bar.c) \
+ $(addprefix configure/,con_cache.c con_connect.c con_content.c \
+ con_fonts.c con_home.c con_image.c con_inter.c con_language.c \
+ con_secure.c con_theme.c)
+
+# This is the final source build list
+# Note this is deliberately *not* expanded here as common and image
+# are not yet available
+SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND)
+
+EXETARGET := !NetSurf/!RunImage$(EXEEXT)
+
+# The filter and target for split messages
+MESSAGES_FILTER=ro
+
+!NetSurf/!Run$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Run $(EXETARGET)
+ $(VQ)echo " MAKERUN: $@"
+ $(Q)$(MAKERUN) $(EXETARGET) $< $@
+
+!NetSurf/!Help$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Help
+ $(VQ)echo " CP: $@"
+ $(Q)cp $< $@
+
+$(DEPROOT)/squeeze.d: $(EXETARGET)
+ $(VQ)echo " SQUEEZE: $<"
+ $(Q)$(SQUEEZE) -f -v $(EXETARGET)
+ $(Q)$(TOUCH) $@
+
+POSTEXES += !NetSurf/!Run$(RUNEXT) !NetSurf/!Help$(RUNEXT) $(DEPROOT)/squeeze.d
+
+
+clean-run:
+ $(VQ)echo " CLEAN: !NetSurf/!Run$(RUNEXT)"
+ $(Q) $(RM) !NetSurf/!Run$(RUNEXT)
+
+clean-help:
+ $(VQ)echo " CLEAN: !NetSurf/!Help$(RUNEXT)"
+ $(Q) $(RM) !NetSurf/!Help$(RUNEXT)
+
+CLEANS += clean-run clean-help
+
+# ----------------------------------------------------------------------------
+# Template targets
+# ----------------------------------------------------------------------------
+
+# Template objects
+TPL_RISCOS := de en fr nl # TODO: It'd be nice to auto-detect these
+TPL_RISCOS := $(addprefix $(FRONTEND_SOURCE_DIR)/templates/,$(TPL_RISCOS))
+
+# Template target creation macro
+define compile_template
+!NetSurf/Resources/$(1)/Templates$$(TPLEXT): $(2)
+ $$(VQ)echo "TEMPLATE: $(2)"
+ $$(Q)mkdir -p !NetSurf/Resources/$(1)
+ $$(Q)$$(CC) -x c -E -P $$(CFLAGS) $(2) | $$(CCRES) - $$@
+
+CLEAN_TEMPLATES += !NetSurf/Resources/$(1)/Templates$$(TPLEXT)
+
+endef
+
+$(eval $(foreach TPL,$(TPL_RISCOS), \
+ $(call compile_template,$(notdir $(TPL)),$(TPL))))
+
+clean-templates:
+ $(VQ)echo " CLEAN: $(CLEAN_TEMPLATES)"
+ $(Q)$(RM) $(CLEAN_TEMPLATES)
+CLEANS += clean-templates
+
+
+# ----------------------------------------------------------------------------
+# Install target
+# ----------------------------------------------------------------------------
+
+install-riscos:
+
+# ----------------------------------------------------------------------------
+# Package target
+# ----------------------------------------------------------------------------
+
+package-riscos: netsurf.zip
+
+netsurf.zip: $(EXETARGET)
+ $(eval $@_TMPDIR := $(shell mktemp -d))
+ $(Q) $(RM) $@
+ $(Q) rsync --archive --verbose $(CURDIR)/!NetSurf $($@_TMPDIR)
+ $(Q) $(CURDIR)/utils/git-date.sh $(FRONTEND_SOURCE_DIR)/distribution
+ $(Q) rsync --archive --verbose $(FRONTEND_SOURCE_DIR)/distribution/!Boot $($@_TMPDIR)
+ $(Q) rsync --archive --verbose $(FRONTEND_SOURCE_DIR)/distribution/!System $($@_TMPDIR)
+ $(Q) rsync --archive --verbose $(FRONTEND_SOURCE_DIR)/distribution/3rdParty $($@_TMPDIR)
+ $(Q) cp $(FRONTEND_SOURCE_DIR)/distribution/ReadMe $($@_TMPDIR)
+ $(Q) cp $(FRONTEND_SOURCE_DIR)/distribution/LeesMij $($@_TMPDIR)
+ $(Q) cd $($@_TMPDIR) && /opt/netsurf/arm-unknown-riscos/env/bin/zip -9vr\, $(CURDIR)/$@ *
+ $(Q) $(RM) -rf $($@_TMPDIR)
diff --git a/frontends/riscos/Makefile.defaults b/frontends/riscos/Makefile.defaults
new file mode 100644
index 000000000..aed361631
--- /dev/null
+++ b/frontends/riscos/Makefile.defaults
@@ -0,0 +1,37 @@
+# ----------------------------------------------------------------------------
+# RISC OS-specific options
+# ----------------------------------------------------------------------------
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO
+NETSURF_USE_NSSVG := YES
+
+# Enable NetSurf's support for displaying RISC OS Draw files
+# Valid options: YES, NO
+NETSURF_USE_DRAW := YES
+
+# Enable NetSurf's support for displaying RISC OS Sprites
+# Valid options: YES, NO
+NETSURF_USE_SPRITE := YES
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
+
+# Enable NetSurf's use of AWRender for displaying ArtWorks files
+# Valid options: YES, NO
+NETSURF_USE_ARTWORKS := YES
+
+# Enable NetSurf's support for the Acorn plugin protocol
+# Valid options: YES, NO
+NETSURF_USE_PLUGINS := NO
+
+# Enable NetSurf's use of pencil for Drawfile export
+# Valid options: YES, NO
+NETSURF_USE_DRAW_EXPORT := YES
+
+# Enable building the source object cache filesystem based backing store.
+NETSURF_FS_BACKING_STORE := YES
+
+# Optimisation levels
+CFLAGS += -O2
diff --git a/frontends/riscos/assert.c b/frontends/riscos/assert.c
new file mode 100644
index 000000000..50b8f5d54
--- /dev/null
+++ b/frontends/riscos/assert.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Assert reporting (RISC OS implementation).
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "oslib/wimp.h"
+
+
+/**
+ * Report an assert() failure and exit.
+ */
+
+void __assert2(const char *expr, const char *function, const char *file,
+ int line)
+{
+ fprintf(stderr, "\n\"%s\", line %d: %s%sAssertion failed: %s\n",
+ file, line,
+ function ? function : "",
+ function ? ": " : "",
+ expr);
+ fflush(stderr);
+
+ abort();
+}
diff --git a/frontends/riscos/bitmap.c b/frontends/riscos/bitmap.c
new file mode 100644
index 000000000..cc4be590c
--- /dev/null
+++ b/frontends/riscos/bitmap.c
@@ -0,0 +1,876 @@
+/*
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2008 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * RISC OS implementation of bitmap operations.
+ *
+ * This implements the interface given by image/bitmap.h using RISC OS
+ * sprites.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <swis.h>
+#include <rufl.h>
+#include <unixlib/local.h>
+#include <oslib/colourtrans.h>
+#include <oslib/osfile.h>
+#include <oslib/osfind.h>
+#include <oslib/osgbpb.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+
+#include "utils/nsoption.h"
+#include "utils/filename.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "desktop/plotters.h"
+#include "content/content.h"
+#include "image/bitmap.h"
+
+#include "riscos/gui.h"
+#include "riscos/image.h"
+#include "riscos/palettes.h"
+#include "riscos/content-handlers/sprite.h"
+#include "riscos/tinct.h"
+#include "riscos/bitmap.h"
+
+/** Colour in the overlay sprite that allows the bitmap to show through */
+#define OVERLAY_INDEX 0xfe
+
+/** Size of buffer used when constructing mask data to be saved */
+#define SAVE_CHUNK_SIZE 4096
+
+/**
+ * Whether we can use 32bpp sprites
+ */
+static int thumbnail_32bpp_available = -1;
+
+/**
+ * Sprite output context saving
+ */
+struct thumbnail_save_area {
+ osspriteop_save_area *save_area;
+ int context1;
+ int context2;
+ int context3;
+};
+
+/**
+ * Initialise a bitmaps sprite area.
+ *
+ * \param bitmap the bitmap to initialise
+ * \return true if bitmap initialised else false.
+ */
+
+static bool bitmap_initialise(struct bitmap *bitmap)
+{
+ unsigned int area_size;
+ osspriteop_area *sprite_area;
+ osspriteop_header *sprite;
+
+ assert(!bitmap->sprite_area);
+
+ area_size = 16 + 44 + bitmap->width * bitmap->height * 4;
+ if (bitmap->state & BITMAP_CLEAR_MEMORY)
+ bitmap->sprite_area = calloc(1, area_size);
+ else
+ bitmap->sprite_area = malloc(area_size);
+
+ if (!bitmap->sprite_area)
+ return false;
+
+ /* area control block */
+ sprite_area = bitmap->sprite_area;
+ sprite_area->size = area_size;
+ sprite_area->sprite_count = 1;
+ sprite_area->first = 16;
+ sprite_area->used = area_size;
+
+ /* sprite control block */
+ sprite = (osspriteop_header *) (sprite_area + 1);
+ sprite->size = area_size - 16;
+ memset(sprite->name, 0x00, 12);
+ strncpy(sprite->name, "bitmap", 12);
+ sprite->width = bitmap->width - 1;
+ sprite->height = bitmap->height - 1;
+ sprite->left_bit = 0;
+ sprite->right_bit = 31;
+ sprite->image = sprite->mask = 44;
+ sprite->mode = tinct_SPRITE_MODE;
+
+ return true;
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+void *riscos_bitmap_create(int width, int height, unsigned int state)
+{
+ struct bitmap *bitmap;
+
+ if (width == 0 || height == 0)
+ return NULL;
+
+ bitmap = calloc(1, sizeof(struct bitmap));
+ if (!bitmap)
+ return NULL;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->state = state;
+
+ return bitmap;
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+unsigned char *riscos_bitmap_get_buffer(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ assert(bitmap);
+
+ /* dynamically create the buffer */
+ if (bitmap->sprite_area == NULL) {
+ if (!bitmap_initialise(bitmap))
+ return NULL;
+ }
+
+ /* image data area should exist */
+ if (bitmap->sprite_area)
+ return ((unsigned char *) (bitmap->sprite_area)) + 16 + 44;
+
+ return NULL;
+}
+
+
+/**
+ * Sets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param opaque whether the bitmap should be plotted opaque
+ */
+static void bitmap_set_opaque(void *vbitmap, bool opaque)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ assert(bitmap);
+
+ if (opaque)
+ bitmap->state |= BITMAP_OPAQUE;
+ else
+ bitmap->state &= ~BITMAP_OPAQUE;
+}
+
+
+/**
+ * Find the width of a pixel row in bytes.
+ *
+ * \param vbitmap A bitmap, as returned by riscos_bitmap_create()
+ * \return width of a pixel row in the bitmap
+ */
+static size_t bitmap_get_rowstride(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ return bitmap->width * 4;
+}
+
+
+/**
+ * Tests whether a bitmap has an opaque alpha channel
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return whether the bitmap is opaque
+ */
+static bool bitmap_test_opaque(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ unsigned char *sprite;
+ unsigned int width, height, size;
+ osspriteop_header *sprite_header;
+ unsigned *p, *ep;
+
+ assert(bitmap);
+
+ sprite = riscos_bitmap_get_buffer(bitmap);
+ if (!sprite)
+ return false;
+
+ width = bitmap_get_rowstride(bitmap);
+
+ sprite_header = (osspriteop_header *) (bitmap->sprite_area + 1);
+
+ height = (sprite_header->height + 1);
+
+ size = width * height;
+
+ p = (void *) sprite;
+
+ ep = (void *) (sprite + (size & ~31));
+ while (p < ep) {
+ /* \todo prefetch(p, 128)? */
+ if (((p[0] & p[1] & p[2] & p[3] & p[4] & p[5] & p[6] & p[7])
+ & 0xff000000U) != 0xff000000U)
+ return false;
+ p += 8;
+ }
+
+ ep = (void *) (sprite + size);
+ while (p < ep) {
+ if ((*p & 0xff000000U) != 0xff000000U) return false;
+ p++;
+ }
+
+ return true;
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+bool riscos_bitmap_get_opaque(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ assert(bitmap);
+ return (bitmap->state & BITMAP_OPAQUE);
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+void riscos_bitmap_destroy(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+
+ assert(bitmap);
+
+ /* destroy bitmap */
+ if (bitmap->sprite_area) {
+ free(bitmap->sprite_area);
+ }
+
+ free(bitmap);
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ os_error *error;
+
+ if (bitmap == NULL) {
+ ro_warn_user("SaveError", messages_get("SprIsNull"));
+ return false;
+ }
+
+ if (!bitmap->sprite_area) {
+ riscos_bitmap_get_buffer(bitmap);
+ }
+ if (!bitmap->sprite_area)
+ return false;
+
+ if (riscos_bitmap_get_opaque(bitmap)) {
+ error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
+ (bitmap->sprite_area), path);
+ if (error) {
+ LOG("xosspriteop_save_sprite_file: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ return false;
+ }
+ return true;
+ } else {
+ /* to make the saved sprite useful we must convert from 'Tinct'
+ * format to either a bi-level mask or a Select-style full
+ * alpha channel */
+ osspriteop_area *area = bitmap->sprite_area;
+ osspriteop_header *hdr = (void *) ((char *) area + area->first);
+ unsigned width = hdr->width + 1, height = hdr->height + 1;
+ unsigned image_size = height * width * 4;
+ unsigned char *chunk_buf;
+ unsigned *p, *elp, *eip;
+ unsigned mask_size;
+ size_t chunk_pix;
+ struct {
+ osspriteop_area area;
+ osspriteop_header hdr;
+ } file_hdr;
+ os_fw fw;
+
+ /* we only support 32bpp sprites */
+ if ((((unsigned)hdr->mode >> 27)&15) != 6) {
+ assert(!"Unsupported sprite format in bitmap_save");
+ return false;
+ }
+
+ chunk_buf = malloc(SAVE_CHUNK_SIZE);
+ if (!chunk_buf) {
+ ro_warn_user("NoMemory", NULL);
+ return false;
+ }
+
+ file_hdr.area = *area;
+ file_hdr.hdr = *hdr;
+
+ if (flags & BITMAP_SAVE_FULL_ALPHA) {
+ mask_size = ((width + 3) & ~3) * height;
+ chunk_pix = SAVE_CHUNK_SIZE;
+ file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode
+ | (1U<<31));
+ } else {
+ mask_size = (((width + 31) & ~31)/8) * height;
+ chunk_pix = SAVE_CHUNK_SIZE<<3;
+ file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode
+ & ~(1U<<31));
+ }
+
+ file_hdr.area.sprite_count = 1;
+ file_hdr.area.first = sizeof(file_hdr.area);
+ file_hdr.area.used = sizeof(file_hdr) + image_size + mask_size;
+
+ file_hdr.hdr.image = sizeof(file_hdr.hdr);
+ file_hdr.hdr.mask = file_hdr.hdr.image + image_size;
+ file_hdr.hdr.size = file_hdr.hdr.mask + mask_size;
+
+ error = xosfind_openoutw(0, path, NULL, &fw);
+ if (error) {
+ LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ free(chunk_buf);
+ ro_warn_user("SaveError", error->errmess);
+ return false;
+ }
+
+ p = (void *) ((char *) hdr + hdr->image);
+
+ /* write out the area header, sprite header and image data */
+ error = xosgbpb_writew(fw, (byte*)&file_hdr + 4,
+ sizeof(file_hdr)-4, NULL);
+ if (!error)
+ error = xosgbpb_writew(fw, (byte*)p, image_size, NULL);
+ if (error) {
+ LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ free(chunk_buf);
+ xosfind_closew(fw);
+ ro_warn_user("SaveError", error->errmess);
+ return false;
+ }
+
+ /* then write out the mask data in chunks */
+ eip = p + (width * height); /* end of image */
+ elp = p + width; /* end of line */
+
+ while (p < eip) {
+ unsigned char *dp = chunk_buf;
+ unsigned *ep = p + chunk_pix;
+ if (ep > elp) ep = elp;
+
+ if (flags & BITMAP_SAVE_FULL_ALPHA) {
+ while (p < ep) {
+ *dp++ = ((unsigned char*)p)[3];
+ p++;
+ }
+ }
+ else {
+ unsigned char mb = 0;
+ int msh = 0;
+ while (p < ep) {
+ if (((unsigned char*)p)[3]) mb |= (1 << msh);
+ if (++msh >= 8) {
+ *dp++ = mb;
+ msh = 0;
+ mb = 0;
+ }
+ p++;
+ }
+ if (msh > 0) *dp++ = mb;
+ }
+
+ if (p >= elp) { /* end of line yet? */
+ /* align to word boundary */
+ while ((int)dp & 3) *dp++ = 0;
+ /* advance end of line pointer */
+ elp += width;
+ }
+ error = xosgbpb_writew(fw, (byte*)chunk_buf, dp-chunk_buf, NULL);
+ if (error) {
+ LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ free(chunk_buf);
+ xosfind_closew(fw);
+ ro_warn_user("SaveError", error->errmess);
+ return false;
+ }
+ }
+
+ error = xosfind_closew(fw);
+ if (error) {
+ LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+
+ error = xosfile_set_type(path, osfile_TYPE_SPRITE);
+ if (error) {
+ LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+
+ free(chunk_buf);
+ return true;
+ }
+}
+
+
+/**
+ * The bitmap image has changed, so flush any persistent cache.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static void bitmap_modified(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ bitmap->state |= BITMAP_MODIFIED;
+}
+
+
+/**
+ * Get the width of a bitmap.
+ *
+ * \param vbitmap A bitmap, as returned by bitmap_create()
+ * \return The bitmaps width in pixels.
+ */
+static int bitmap_get_width(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ return bitmap->width;
+}
+
+
+/**
+ * Get the height of a bitmap.
+ *
+ * \param vbitmap A bitmap, as returned by bitmap_create()
+ * \return The bitmaps height in pixels.
+ */
+static int bitmap_get_height(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *) vbitmap;
+ return bitmap->height;
+}
+
+
+/**
+ * Find the bytes per pixel of a bitmap
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return bytes per pixel
+ */
+static size_t bitmap_get_bpp(void *vbitmap)
+{
+ struct bitmap *bitmap = (struct bitmap *)vbitmap;
+ assert(bitmap);
+ return 4;
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+void riscos_bitmap_overlay_sprite(struct bitmap *bitmap,
+ const osspriteop_header *s)
+{
+ const os_colour *palette;
+ const byte *sp, *mp;
+ bool masked = false;
+ bool alpha = false;
+ os_error *error;
+ int dp_offset;
+ int sp_offset;
+ unsigned *dp;
+ int x, y;
+ int w, h;
+
+ assert(sprite_bpp(s) == 8);
+
+ if ((unsigned)s->mode & 0x80000000U)
+ alpha = true;
+
+ error = xosspriteop_read_sprite_info(osspriteop_PTR,
+ (osspriteop_area *)0x100,
+ (osspriteop_id)s,
+ &w, &h, NULL, NULL);
+ if (error) {
+ LOG("xosspriteop_read_sprite_info: 0x%x:%s", error->errnum, error->errmess);
+ return;
+ }
+ sp_offset = ((s->width + 1) * 4) - w;
+
+ if (w > bitmap->width)
+ w = bitmap->width;
+ if (h > bitmap->height)
+ h = bitmap->height;
+
+ dp_offset = bitmap_get_rowstride(bitmap) / 4;
+
+ dp = (void*)riscos_bitmap_get_buffer(bitmap);
+ if (!dp)
+ return;
+ sp = (byte*)s + s->image;
+ mp = (byte*)s + s->mask;
+
+ sp += s->left_bit / 8;
+ mp += s->left_bit / 8;
+
+ if (s->image > (int)sizeof(*s))
+ palette = (os_colour*)(s + 1);
+ else
+ palette = default_palette8;
+
+ if (s->mask != s->image) {
+ masked = true;
+ bitmap_set_opaque(bitmap, false);
+ }
+
+ /* (partially-)transparent pixels in the overlayed sprite retain
+ * their transparency in the output bitmap; opaque sprite pixels
+ * are also propagated to the bitmap, except those which are the
+ * OVERLAY_INDEX colour which allow the original bitmap contents to
+ * show through */
+ for (y = 0; y < h; y++) {
+ unsigned *sdp = dp;
+ for(x = 0; x < w; x++) {
+ os_colour d = ((unsigned)palette[(*sp) << 1]) >> 8;
+ if (*sp++ == OVERLAY_INDEX)
+ d = *dp;
+ if (masked) {
+ if (alpha)
+ d |= ((*mp << 24) ^ 0xff000000U);
+ else if (*mp)
+ d |= 0xff000000U;
+ }
+ *dp++ = d;
+ mp++;
+ }
+ dp = sdp + dp_offset;
+ sp += sp_offset;
+ mp += sp_offset;
+ }
+}
+
+
+/**
+ * Creates an 8bpp canvas.
+ *
+ * \param bitmap the bitmap to clone the size of
+ * \return a sprite area containing an 8bpp sprite
+ */
+static osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap)
+{
+ unsigned image_size = ((bitmap->width + 3) & ~3) * bitmap->height;
+ bool opaque = riscos_bitmap_get_opaque(bitmap);
+ osspriteop_header *sprite_header = NULL;
+ osspriteop_area *sprite_area = NULL;
+ unsigned area_size;
+
+ /* clone the sprite */
+ area_size = sizeof(osspriteop_area) +
+ sizeof(osspriteop_header) +
+ image_size +
+ 2048;
+
+ if (!opaque) area_size += image_size;
+
+ sprite_area = (osspriteop_area *)malloc(area_size);
+ if (!sprite_area) {
+ LOG("no memory for malloc()");
+ return NULL;
+ }
+ sprite_area->size = area_size;
+ sprite_area->sprite_count = 1;
+ sprite_area->first = 16;
+ sprite_area->used = area_size;
+ sprite_header = (osspriteop_header *)(sprite_area + 1);
+ sprite_header->size = area_size - sizeof(osspriteop_area);
+ memset(sprite_header->name, 0x00, 12);
+ strcpy(sprite_header->name, "bitmap");
+ sprite_header->left_bit = 0;
+ sprite_header->height = bitmap->height - 1;
+ sprite_header->mode = os_MODE8BPP90X90;
+ sprite_header->right_bit = ((bitmap->width << 3) - 1) & 31;
+ sprite_header->width = ((bitmap->width + 3) >> 2) - 1;
+ sprite_header->image = sizeof(osspriteop_header) + 2048;
+ sprite_header->mask = sizeof(osspriteop_header) + 2048;
+ if (!opaque) sprite_header->mask += image_size;
+
+ /* create the palette. we don't read the necessary size like
+ * we really should as we know it's going to have 256 entries
+ * of 8 bytes = 2048. */
+ xcolourtrans_read_palette((osspriteop_area *)os_MODE8BPP90X90,
+ (osspriteop_id)0,
+ (os_palette *)(sprite_header + 1), 2048,
+ (colourtrans_palette_flags)(1 << 1), 0);
+ return sprite_area;
+}
+
+
+/**
+ * Switches output to the specified sprite and returns the previous context.
+ */
+static struct thumbnail_save_area*
+thumbnail_switch_output(osspriteop_area *sprite_area,
+ osspriteop_header *sprite_header)
+{
+ struct thumbnail_save_area *save_area;
+ int size;
+
+ /* create a save area */
+ save_area = calloc(sizeof(struct thumbnail_save_area), 1);
+ if (save_area == NULL) return NULL;
+
+ /* allocate OS_SpriteOp save area */
+ if (xosspriteop_read_save_area_size(osspriteop_PTR, sprite_area,
+ (osspriteop_id)sprite_header, &size)) {
+ free(save_area);
+ return NULL;
+ }
+
+ /* create the save area */
+ save_area->save_area = malloc((unsigned)size);
+ if (save_area->save_area == NULL) {
+ free(save_area);
+ return NULL;
+ }
+ save_area->save_area->a[0] = 0;
+
+ /* switch output to sprite */
+ if (xosspriteop_switch_output_to_sprite(osspriteop_PTR, sprite_area,
+ (osspriteop_id)sprite_header, save_area->save_area,
+ 0, &save_area->context1, &save_area->context2,
+ &save_area->context3)) {
+ free(save_area->save_area);
+ free(save_area);
+ return NULL;
+ }
+ return save_area;
+}
+
+
+/**
+ * Restores output to the specified context, and destroys it.
+ */
+static void thumbnail_restore_output(struct thumbnail_save_area *save_area)
+{
+ /* we don't care if we err, as there's nothing we can do about it */
+ xosspriteop_switch_output_to_sprite(osspriteop_PTR,
+ (osspriteop_area *)save_area->context1,
+ (osspriteop_id)save_area->context2,
+ (osspriteop_save_area *)save_area->context3,
+ 0, 0, 0, 0);
+ free(save_area->save_area);
+ free(save_area);
+}
+
+
+/**
+ * Convert a bitmap to 8bpp.
+ *
+ * \param bitmap the bitmap to convert
+ * \return a sprite area containing an 8bpp sprite
+ */
+osspriteop_area *riscos_bitmap_convert_8bpp(struct bitmap *bitmap)
+{
+ struct thumbnail_save_area *save_area;
+ osspriteop_area *sprite_area = NULL;
+ osspriteop_header *sprite_header = NULL;
+
+ sprite_area = thumbnail_create_8bpp(bitmap);
+ if (!sprite_area)
+ return NULL;
+ sprite_header = (osspriteop_header *)(sprite_area + 1);
+
+
+ /* switch output and redraw */
+ save_area = thumbnail_switch_output(sprite_area, sprite_header);
+ if (save_area == NULL) {
+ if (thumbnail_32bpp_available != 1)
+ free(sprite_area);
+ return false;
+ }
+ _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
+ (osspriteop_header *)(bitmap->sprite_area + 1),
+ 0, 0,
+ tinct_ERROR_DIFFUSE);
+ thumbnail_restore_output(save_area);
+
+ if (sprite_header->image != sprite_header->mask) {
+ /* build the sprite mask from the alpha channel */
+ void *buf = riscos_bitmap_get_buffer(bitmap);
+ unsigned *dp = (unsigned *) buf;
+ if (!dp)
+ return sprite_area;
+ int w = bitmap_get_width(bitmap);
+ int h = bitmap_get_height(bitmap);
+ int dp_offset = bitmap_get_rowstride(bitmap) / 4 - w;
+ int mp_offset = ((sprite_header->width + 1) * 4) - w;
+ byte *mp = (byte*)sprite_header + sprite_header->mask;
+ bool alpha = ((unsigned)sprite_header->mode & 0x80000000U) != 0;
+
+ while (h-- > 0) {
+ int x = 0;
+ for(x = 0; x < w; x++) {
+ unsigned d = *dp++;
+ if (alpha)
+ *mp++ = (d >> 24) ^ 0xff;
+ else
+ *mp++ = (d < 0xff000000U) ? 0 : 0xff;
+ }
+ dp += dp_offset;
+ mp += mp_offset;
+ }
+ }
+
+ return sprite_area;
+}
+
+
+
+
+/**
+ * Check to see whether 32bpp sprites are available.
+ *
+ * Rather than using Wimp_ReadSysInfo we test if 32bpp sprites are available
+ * in case the user has a 3rd party patch to enable them.
+ */
+static void thumbnail_test(void)
+{
+ unsigned int area_size;
+ osspriteop_area *sprite_area;
+
+ /* try to create a 1x1 32bpp sprite */
+ area_size = sizeof(osspriteop_area) +
+ sizeof(osspriteop_header) + sizeof(int);
+ if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
+ LOG("Insufficient memory to perform sprite test.");
+ return;
+ }
+ sprite_area->size = area_size + 1;
+ sprite_area->sprite_count = 0;
+ sprite_area->first = 16;
+ sprite_area->used = 16;
+ if (xosspriteop_create_sprite(osspriteop_NAME, sprite_area,
+ "test", false, 1, 1, (os_mode)tinct_SPRITE_MODE))
+ thumbnail_32bpp_available = 0;
+ else
+ thumbnail_32bpp_available = 1;
+ free(sprite_area);
+}
+
+
+/* exported interface documented in riscos/bitmap.h */
+nserror riscos_bitmap_render(struct bitmap *bitmap,
+ struct hlcache_handle *content)
+{
+ struct thumbnail_save_area *save_area;
+ osspriteop_area *sprite_area = NULL;
+ osspriteop_header *sprite_header = NULL;
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+
+ assert(content);
+ assert(bitmap);
+
+ LOG("content %p in bitmap %p", content, bitmap);
+
+ /* check if we have access to 32bpp sprites natively */
+ if (thumbnail_32bpp_available == -1) {
+ thumbnail_test();
+ }
+
+ /* if we don't support 32bpp sprites then we redirect to an 8bpp
+ * image and then convert back.
+ */
+ if (thumbnail_32bpp_available != 1) {
+ sprite_area = thumbnail_create_8bpp(bitmap);
+ if (!sprite_area)
+ return false;
+ sprite_header = (osspriteop_header *)(sprite_area + 1);
+ } else {
+ const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap);
+ if (!pixbufp || !bitmap->sprite_area)
+ return false;
+ sprite_area = bitmap->sprite_area;
+ sprite_header = (osspriteop_header *)(sprite_area + 1);
+ }
+
+ /* set up the plotters */
+ ro_plot_origin_x = 0;
+ ro_plot_origin_y = bitmap->height * 2;
+
+ /* switch output and redraw */
+ save_area = thumbnail_switch_output(sprite_area, sprite_header);
+ if (!save_area) {
+ if (thumbnail_32bpp_available != 1)
+ free(sprite_area);
+ return false;
+ }
+ rufl_invalidate_cache();
+ colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG_GCOL,
+ os_ACTION_OVERWRITE, 0);
+
+ /* render the content */
+ content_scaled_redraw(content, bitmap->width, bitmap->height, &ctx);
+
+ thumbnail_restore_output(save_area);
+ rufl_invalidate_cache();
+
+ /* if we changed to 8bpp then go back to 32bpp */
+ if (thumbnail_32bpp_available != 1) {
+ const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap);
+ _kernel_oserror *error;
+
+ if (!pixbufp || !bitmap->sprite_area) {
+ free(sprite_area);
+ return false;
+ }
+ error = _swix(Tinct_ConvertSprite, _INR(2,3),
+ sprite_header,
+ (osspriteop_header *)(bitmap->sprite_area + 1));
+ free(sprite_area);
+ if (error)
+ return false;
+ }
+
+ bitmap_modified(bitmap);
+
+ return NSERROR_OK;
+}
+
+static struct gui_bitmap_table bitmap_table = {
+ .create = riscos_bitmap_create,
+ .destroy = riscos_bitmap_destroy,
+ .set_opaque = bitmap_set_opaque,
+ .get_opaque = riscos_bitmap_get_opaque,
+ .test_opaque = bitmap_test_opaque,
+ .get_buffer = riscos_bitmap_get_buffer,
+ .get_rowstride = bitmap_get_rowstride,
+ .get_width = bitmap_get_width,
+ .get_height = bitmap_get_height,
+ .get_bpp = bitmap_get_bpp,
+ .save = riscos_bitmap_save,
+ .modified = bitmap_modified,
+ .render = riscos_bitmap_render,
+};
+
+struct gui_bitmap_table *riscos_bitmap_table = &bitmap_table;
diff --git a/frontends/riscos/bitmap.h b/frontends/riscos/bitmap.h
new file mode 100644
index 000000000..3aca30de6
--- /dev/null
+++ b/frontends/riscos/bitmap.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_RISCOS_BITMAP_H_
+#define _NETSURF_RISCOS_BITMAP_H_
+
+struct osspriteop_area;
+struct osspriteop_header;
+struct hlcache_handle;
+struct bitmap;
+
+/** bitmap operations table */
+struct gui_bitmap_table *riscos_bitmap_table;
+
+/** save with full alpha channel (if not opaque) */
+#define BITMAP_SAVE_FULL_ALPHA (1 << 0)
+
+/**
+ * RISC OS wimp toolkit bitmap.
+ */
+struct bitmap {
+ int width; /**< width of bitmap */
+ int height; /**< height of bitmap */
+
+ unsigned int state; /**< The bitmap attributes (opaque/dirty etc.) */
+
+ struct osspriteop_area *sprite_area; /**< Uncompressed data, or NULL */
+};
+
+/**
+ * Convert bitmap to 8bpp sprite.
+ *
+ * \param bitmap the bitmap to convert.
+ * \return The converted sprite.
+ */
+struct osspriteop_area *riscos_bitmap_convert_8bpp(struct bitmap *bitmap);
+
+/**
+ * Render content into bitmap.
+ *
+ * \param bitmap the bitmap to draw to
+ * \param content content structure to render
+ * \return true on success and bitmap updated else false
+ */
+nserror riscos_bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content);
+
+/**
+ * Overlay a sprite onto the given bitmap
+ *
+ * \param bitmap bitmap object
+ * \param s 8bpp sprite to be overlayed onto bitmap
+ */
+void riscos_bitmap_overlay_sprite(struct bitmap *bitmap, const struct osspriteop_header *s);
+
+/**
+ * Create a bitmap.
+ *
+ * \param width width of image in pixels
+ * \param height width of image in pixels
+ * \param state the state to create the bitmap in.
+ * \return an opaque struct bitmap, or NULL on memory exhaustion
+ */
+void *riscos_bitmap_create(int width, int height, unsigned int state);
+
+/**
+ * Free a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+void riscos_bitmap_destroy(void *vbitmap);
+
+/**
+ * Return a pointer to the pixel data in a bitmap.
+ *
+ * The pixel data is packed as BITMAP_FORMAT, possibly with padding at
+ * the end of rows. The width of a row in bytes is given by
+ * riscos_bitmap_get_rowstride().
+ *
+ * \param vbitmap A bitmap as returned by riscos_bitmap_create()
+ * \return pointer to the pixel buffer
+ */
+unsigned char *riscos_bitmap_get_buffer(void *vbitmap);
+
+/**
+ * Gets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap A bitmap, as returned by riscos_bitmap_create()
+ */
+bool riscos_bitmap_get_opaque(void *vbitmap);
+
+/**
+ * Save a bitmap in the platform's native format.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param path pathname for file
+ * \param flags modify the behaviour of the save
+ * \return true on success, false on error and error reported
+ */
+bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags);
+
+#endif
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c
new file mode 100644
index 000000000..7176c1c1c
--- /dev/null
+++ b/frontends/riscos/buffer.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <swis.h>
+#include <oslib/colourtrans.h>
+#include <oslib/os.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpreadsysinfo.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+
+#include "riscos/buffer.h"
+#include "riscos/gui.h"
+#include "riscos/tinct.h"
+#include "riscos/wimp.h"
+#include "riscos/wimputils.h"
+
+#define BUFFER_EXCLUSIVE_USER_REDRAW "Only support pure user redraw (faster)"
+//#define BUFFER_EMULATE_32BPP "Redirect to a 32bpp sprite and plot with Tinct"
+
+/** Absent from OSLib
+*/
+#ifndef osspriteop_TYPEEXPANSION
+#define osspriteop_TYPEEXPANSION ((osspriteop_mode_word) 0xFu)
+#endif
+#ifndef osspriteop_TYPE16BPP4K
+#define osspriteop_TYPE16BPP4K ((osspriteop_mode_word) 0x10u)
+#endif
+
+static void ro_gui_buffer_free(void);
+
+
+/** The buffer characteristics
+*/
+static osspriteop_area *buffer = NULL;
+static char buffer_name[12] = "scr_buffer";
+
+/** The current clip area
+*/
+static os_box clipping;
+
+/** The current save area
+*/
+static osspriteop_save_area *save_area;
+static int context0;
+static int context1;
+static int context2;
+static int context3;
+
+/** The current sprite mode
+*/
+static os_mode mode;
+
+
+/**
+ * Opens a buffer for writing to.
+ *
+ * The ro_plot_origin_ variables are updated to reflect the new screen origin,
+ * so the variables should be set before calling this function, and not
+ * changed until after ro_gui_buffer_close() has been called.
+ *
+ * \param redraw the current WIMP redraw area to buffer
+ */
+void ro_gui_buffer_open(wimp_draw *redraw)
+{
+ int size;
+ int total_size;
+ os_coord sprite_size;
+ int bpp, word_width;
+ bool palette;
+ os_error *error;
+ int palette_size = 0;
+#ifdef BUFFER_EXCLUSIVE_USER_REDRAW
+ osspriteop_header *header;
+#endif
+
+ /* Close any open buffer
+ */
+ if (buffer)
+ ro_gui_buffer_close();
+
+ /* Store our clipping region
+ */
+ clipping = redraw->clip;
+
+ /* Stop bad rectangles
+ */
+ if ((clipping.x1 < clipping.x0) ||
+ (clipping.y1 < clipping.y0)) {
+ LOG("Invalid clipping rectangle (%i, %i) to (%i,%i)", clipping.x0, clipping.y0, clipping.x1, clipping.y1);
+ return;
+ }
+
+ /* Work out how much buffer we need
+ */
+ sprite_size.x = clipping.x1 - clipping.x0 + 1;
+ sprite_size.y = clipping.y1 - clipping.y0 + 1;
+ ro_convert_os_units_to_pixels(&sprite_size, (os_mode)-1);
+ if (sprite_size.y == 1) /* work around SpriteExtend bug */
+ sprite_size.y = 2;
+
+#ifdef BUFFER_EMULATE_32BPP
+ bpp = 5;
+ palette = false;
+#else
+ /* Get the screen depth as we can't use palettes for >8bpp
+ */
+ xos_read_mode_variable((os_mode)-1, os_MODEVAR_LOG2_BPP, &bpp, 0);
+ palette = (bpp < 4);
+#endif
+
+ /* Get our required buffer size
+ */
+ word_width = ((sprite_size.x << bpp) + 31) >> 5;
+ if (palette)
+ palette_size = ((1 << (1 << bpp)) << 3);
+ total_size = sizeof(osspriteop_area) + sizeof(osspriteop_header) +
+ (word_width * sprite_size.y * 4) + palette_size;
+ buffer = (osspriteop_area *)malloc(total_size);
+ if (!buffer) {
+ LOG("Failed to allocate memory");
+ ro_gui_buffer_free();
+ return;
+ }
+ buffer->size = total_size;
+ buffer->first = 16;
+
+#ifdef BUFFER_EMULATE_32BPP
+ mode = tinct_SPRITE_MODE;
+#else
+ if ((error = xwimpreadsysinfo_wimp_mode(&mode)) != NULL) {
+ LOG("Error reading mode '%s'", error->errmess);
+ ro_gui_buffer_free();
+ return;
+ }
+
+ /* if we're not in a numbered screen mode then we need
+ to build a suitable sprite mode word */
+ if (mode >= (os_mode)0x100) {
+ static const ns_os_vdu_var_list vars = {
+ os_MODEVAR_LOG2_BPP,
+ {
+ os_MODEVAR_MODE_FLAGS,
+ os_MODEVAR_NCOLOUR,
+ os_MODEVAR_XEIG_FACTOR,
+ os_MODEVAR_YEIG_FACTOR,
+ os_VDUVAR_END_LIST
+ }
+ };
+ struct {
+ int log2bpp;
+ int flags;
+ int ncolour;
+ int xeig, yeig;
+ } vals;
+ int type;
+
+ error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), (int *)&vals);
+ if (error) {
+ LOG("Error reading mode properties '%s'", error->errmess);
+ ro_gui_buffer_free();
+ return;
+ }
+
+ switch (vals.ncolour) {
+ case 1:
+ case 3:
+ case 15:
+ case 63:
+ case 255:
+ /* Paletted modes are pixel packing order agnostic */
+ type = 1 + vals.log2bpp;
+ mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
+ ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
+ break;
+ case 4095:
+ /* 16bpp 4k colours */
+ type = osspriteop_TYPE16BPP4K;
+ mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ (vals.yeig << 6) |
+ (vals.xeig << 4) |
+ (type << 20) |
+ (vals.flags & 0xFF00));
+ break;
+ case 65535:
+ switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) {
+ case os_MODE_FLAG_DATA_FORMAT_RGB:
+ if (vals.flags & 0xC000) {
+ /* Non VIDC packing order */
+ if (vals.flags & os_MODE_FLAG_FULL_PALETTE)
+ type = osspriteop_TYPE16BPP64K;
+ else
+ type = osspriteop_TYPE16BPP;
+ mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ (vals.yeig << 6) |
+ (vals.xeig << 4) |
+ (type << 20) |
+ (vals.flags & 0xFF00));
+ } else {
+ /* VIDC packing order */
+ if (vals.flags & os_MODE_FLAG_FULL_PALETTE)
+ type = osspriteop_TYPE16BPP64K;
+ else
+ type = osspriteop_TYPE16BPP;
+ mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
+ ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
+ }
+ break;
+ default:
+ LOG("Unhandled 16bpp format from flags %d", vals.flags);
+ ro_gui_buffer_free();
+ return;
+ }
+ break;
+ case -1:
+ /* 16M colours */
+ switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) {
+ case os_MODE_FLAG_DATA_FORMAT_RGB:
+ if (vals.flags & 0xC000) {
+ /* Non VIDC packing order */
+ type = osspriteop_TYPE32BPP;
+ mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ (vals.yeig << 6) |
+ (vals.xeig << 4) |
+ (type << 20) |
+ (vals.flags & 0xFF00));
+ } else {
+ /* VIDC packing order */
+ type = osspriteop_TYPE32BPP;
+ mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
+ osspriteop_NEW_STYLE |
+ ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
+ ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
+ }
+ break;
+ default:
+ LOG("Unhandled 32bpp data format from flags %d", vals.flags);
+ ro_gui_buffer_free();
+ return;
+ }
+ break;
+ default:
+ LOG("Unhandled NCOLOUR value %d", vals.ncolour);
+ ro_gui_buffer_free();
+ return;
+ }
+ }
+#endif
+
+#ifdef BUFFER_EXCLUSIVE_USER_REDRAW
+ /* Create the sprite manually so we don't waste time clearing the
+ background.
+ */
+ buffer->sprite_count = 1;
+ buffer->used = total_size;
+ header = (osspriteop_header *)(buffer + 1);
+ header->size = total_size - sizeof(osspriteop_area);
+ memcpy(header->name, buffer_name, 12);
+ header->width = word_width - 1;
+ header->height = sprite_size.y - 1;
+ header->left_bit = 0;
+ header->right_bit = ((sprite_size.x << bpp) - 1) & 31;
+ header->image = sizeof(osspriteop_header) + palette_size;
+ header->mask = header->image;
+ header->mode = mode;
+ if (palette)
+ xcolourtrans_read_palette((osspriteop_area *)mode,
+ (osspriteop_id)os_CURRENT_MODE,
+ (os_palette *)(header + 1), palette_size,
+ (colourtrans_palette_flags)
+ colourtrans_FLASHING_PALETTE, 0);
+#else
+ /* Read the current contents of the screen
+ */
+ buffer->sprite_count = 0;
+ buffer->used = 16;
+ if ((error = xosspriteop_get_sprite_user_coords(osspriteop_NAME,
+ buffer, buffer_name, palette,
+ clipping.x0, clipping.y0,
+ clipping.x1, clipping.y1)) != NULL) {
+ LOG("Grab error '%s'", error->errmess);
+ ro_gui_buffer_free();
+ return;
+ }
+#endif
+ /* Allocate OS_SpriteOp save area
+ */
+ if ((error = xosspriteop_read_save_area_size(osspriteop_PTR,
+ buffer, (osspriteop_id)(buffer + 1), &size)) != NULL) {
+ LOG("Save area error '%s'", error->errmess);
+ ro_gui_buffer_free();
+ return;
+ }
+ if ((save_area = malloc((size_t)size)) == NULL) {
+ ro_gui_buffer_free();
+ return;
+ }
+ save_area->a[0] = 0;
+
+ /* Switch output to sprite
+ */
+ if ((error = xosspriteop_switch_output_to_sprite(osspriteop_PTR,
+ buffer, (osspriteop_id)(buffer + 1), save_area,
+ &context0, &context1, &context2, &context3)) != NULL) {
+ LOG("Switching error '%s'", error->errmess);
+ free(save_area);
+ ro_gui_buffer_free();
+ return;
+ }
+
+ /* Emulate an origin as the FontManager doesn't respect it in
+ most cases.
+ */
+ ro_plot_origin_x -= clipping.x0;
+ ro_plot_origin_y -= clipping.y0;
+
+ /* Update the ECF origin
+ */
+ if ((error = xos_set_ecf_origin(-ro_plot_origin_x,
+ -ro_plot_origin_y)) != NULL) {
+ LOG("Invalid ECF origin: '%s'", error->errmess);
+ }
+}
+
+
+/**
+ * Closes any open buffer and flushes the contents to screen
+ */
+void ro_gui_buffer_close(void)
+{
+ /* Check we have an open buffer
+ */
+ if (!buffer)
+ return;
+
+ /* Remove any previous redirection
+ */
+ ro_plot_origin_x += clipping.x0;
+ ro_plot_origin_y += clipping.y0;
+ xosspriteop_unswitch_output(context0, context1, context2, context3);
+ free(save_area);
+
+ /* Plot the contents to screen
+ */
+ if (mode == tinct_SPRITE_MODE)
+ _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
+ (char *)(buffer + 1),
+ clipping.x0, clipping.y0,
+ nsoption_int(plot_fg_quality));
+ else
+ xosspriteop_put_sprite_user_coords(osspriteop_PTR,
+ buffer, (osspriteop_id)(buffer + 1),
+ clipping.x0, clipping.y0, (os_action)0);
+ ro_gui_buffer_free();
+
+ /* Update the ECF origin
+ */
+ os_set_ecf_origin(0, 0);
+}
+
+
+/**
+ * Releases any buffer memory depending on cache constraints.
+ */
+static void ro_gui_buffer_free(void)
+{
+ free(buffer);
+ buffer = NULL;
+}
diff --git a/frontends/riscos/buffer.h b/frontends/riscos/buffer.h
new file mode 100644
index 000000000..a683c324c
--- /dev/null
+++ b/frontends/riscos/buffer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Screen buffering (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_BUFFER_H_
+#define _NETSURF_RISCOS_BUFFER_H_
+
+#include "oslib/wimp.h"
+
+void ro_gui_buffer_open(wimp_draw *redraw);
+void ro_gui_buffer_close(void);
+
+#endif
diff --git a/frontends/riscos/configure.c b/frontends/riscos/configure.c
new file mode 100644
index 000000000..9d28616ec
--- /dev/null
+++ b/frontends/riscos/configure.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * RISC OS option setting (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <oslib/os.h>
+#include <oslib/osbyte.h>
+#include <oslib/territory.h>
+#include <oslib/wimp.h>
+
+#include "utils/log.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/dialog.h"
+#include "riscos/configure.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure/configure.h"
+
+#define CONFIGURE_ICON_PADDING_H 32
+#define CONFIGURE_ICON_PADDING_V 32
+#define CONFIGURE_DEFAULT_ICON_WIDTH (68 + CONFIGURE_ICON_PADDING_H)
+#define CONFIGURE_DEFAULT_ICON_HEIGHT (128 + CONFIGURE_ICON_PADDING_V)
+
+struct configure_tool {
+ const char *name;
+#define CONFIGURE_TOOL_TRANSLATED_SIZE 64
+ char translated[CONFIGURE_TOOL_TRANSLATED_SIZE];
+ char *validation;
+ bool (*initialise)(wimp_w w);
+ void (*finalise)(wimp_w w);
+ wimp_w w;
+ wimp_i i;
+ bool open;
+ struct configure_tool *next;
+};
+
+static wimp_w configure_window;
+static int configure_current_encoding;
+static int configure_icons = 0;
+static struct configure_tool *configure_tools = NULL;
+static int configure_icon_width = CONFIGURE_DEFAULT_ICON_WIDTH;
+static int configure_icon_height = CONFIGURE_DEFAULT_ICON_HEIGHT;
+static int configure_icons_per_line = 0;
+static int configure_width;
+static int configure_height;
+
+static bool ro_gui_configure_click(wimp_pointer *pointer);
+static void ro_gui_configure_open_window(wimp_open *open);
+static void ro_gui_configure_close(wimp_w w);
+static bool ro_gui_configure_translate(void);
+static void ro_gui_configure_register(const char *window,
+ bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w));
+
+void ro_gui_configure_initialise(void)
+{
+ /* create our window */
+ configure_window = ro_gui_dialog_create("configure");
+ ro_gui_wimp_event_register_open_window(configure_window,
+ ro_gui_configure_open_window);
+ ro_gui_wimp_event_register_mouse_click(configure_window,
+ ro_gui_configure_click);
+ ro_gui_wimp_event_set_help_prefix(configure_window, "HelpConfigure");
+
+ /* add in our option windows */
+ ro_gui_configure_register("con_cache",
+ ro_gui_options_cache_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_connect",
+ ro_gui_options_connection_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_content",
+ ro_gui_options_content_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_fonts",
+ ro_gui_options_fonts_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_home",
+ ro_gui_options_home_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_image",
+ ro_gui_options_image_initialise,
+ ro_gui_options_image_finalise);
+ ro_gui_configure_register("con_inter",
+ ro_gui_options_interface_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_lang",
+ ro_gui_options_language_initialise,
+ ro_gui_wimp_event_finalise);
+ ro_gui_configure_register("con_theme",
+ ro_gui_options_theme_initialise,
+ ro_gui_options_theme_finalise);
+ ro_gui_configure_register("con_secure",
+ ro_gui_options_security_initialise,
+ ro_gui_wimp_event_finalise);
+
+ /* translate the icons */
+ if (!ro_gui_configure_translate())
+ die("ro_gui_configure_translate failed");
+}
+
+void ro_gui_configure_show(void)
+{
+ int width, height;
+
+ width = configure_icon_width << 2;
+ height = ((configure_icons + 3) >> 2) * configure_icon_height;
+ ro_gui_dialog_open_top(configure_window, NULL, width, height);
+}
+
+bool ro_gui_configure_click(wimp_pointer *pointer)
+{
+ struct configure_tool *tool;
+
+ if (pointer->buttons == wimp_CLICK_MENU)
+ return true;
+
+ for (tool = configure_tools; tool; tool = tool->next) {
+ if (tool->i == pointer->i) {
+ if (!tool->open) {
+ tool->open = true;
+ if (!tool->initialise(tool->w))
+ return false;
+ ro_gui_dialog_open_persistent(
+ configure_window,
+ tool->w, true);
+ ro_gui_wimp_event_register_close_window(
+ tool->w,
+ ro_gui_configure_close);
+ } else {
+ ro_gui_dialog_open_top(tool->w, NULL, 0, 0);
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+void ro_gui_configure_close(wimp_w w)
+{
+ struct configure_tool *tool;
+
+ for (tool = configure_tools; tool; tool = tool->next) {
+ if (tool->w == w) {
+ tool->open = false;
+ if (tool->finalise)
+ tool->finalise(w);
+ break;
+ }
+ }
+}
+
+void ro_gui_configure_open_window(wimp_open *open)
+{
+ os_error *error;
+ int screen_width, screen_height;
+ int height, width;
+ int icons_per_line, icon_lines;
+ int max_height;
+ os_box extent = { 0, 0, 0, 0 };
+ struct configure_tool *tool;
+
+ if (!ro_gui_configure_translate()) {
+ ro_warn_user("ro_gui_configure_translate failed", 0);
+ return;
+ }
+
+ width = open->visible.x1 - open->visible.x0;
+ height = open->visible.y1 - open->visible.y0;
+ icons_per_line = width / configure_icon_width;
+ if (icons_per_line < 1)
+ icons_per_line = 1;
+
+ /* move our icons */
+ if (icons_per_line != configure_icons_per_line) {
+ int x, y, l;
+ configure_icons_per_line = icons_per_line;
+ x = CONFIGURE_ICON_PADDING_H / 2;
+ y = -configure_icon_height + (CONFIGURE_ICON_PADDING_V / 2);
+ l = 0;
+ for (tool = configure_tools; tool; tool = tool->next) {
+ error = xwimp_resize_icon(configure_window,
+ tool->i,
+ x,
+ y,
+ x + configure_icon_width -
+ CONFIGURE_ICON_PADDING_H,
+ y + configure_icon_height -
+ CONFIGURE_ICON_PADDING_V);
+ if (error) {
+ LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ }
+ x += configure_icon_width;
+ l++;
+ if (l >= icons_per_line) {
+ x = CONFIGURE_ICON_PADDING_H / 2;
+ l = 0;
+ y -= configure_icon_height;
+ }
+ }
+ error = xwimp_force_redraw(configure_window,
+ 0, -16384, 16384, 0);
+ if (error) {
+ LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+
+ /* restrict our height */
+ icon_lines = (configure_icons + icons_per_line - 1) /
+ icons_per_line;
+ max_height = (icon_lines * configure_icon_height);
+ if (height > max_height)
+ open->visible.y0 = open->visible.y1 - max_height;
+
+ /* set the extent */
+ if ((configure_height != height) || (configure_width != width)) {
+ int max_icons_per_line;
+ ro_gui_screen_size(&screen_width, &screen_height);
+ max_icons_per_line = screen_width / configure_icon_width;
+ if (max_icons_per_line > configure_icons)
+ max_icons_per_line = configure_icons;
+ extent.x1 = configure_icon_width * max_icons_per_line;
+ extent.y0 = -max_height;
+ error = xwimp_set_extent(open->w, &extent);
+ if (error) {
+ LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ configure_height = height;
+ configure_width = width;
+ }
+
+ /* open the window */
+ error = xwimp_open_window(open);
+ if (error) {
+ LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+}
+
+void ro_gui_configure_register(const char *window,
+ bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w))
+{
+ wimp_icon_create new_icon;
+ struct configure_tool *tool;
+ struct configure_tool *link;
+ os_error *error;
+
+ /* create our tool */
+ tool = calloc(sizeof(struct configure_tool), 1);
+ if (!tool) {
+ LOG("Insufficient memory for calloc()");
+ die("Insufficient memory");
+ return; /* For the benefit of scan-build */
+ }
+ tool->name = window;
+ tool->translated[0] = '\0';
+ tool->validation = malloc(strlen(window) + 2);
+ if (!tool->validation) {
+ LOG("Insufficient memory for malloc()");
+ die("Insufficient memory");
+ }
+ sprintf(tool->validation, "S%s", window);
+ tool->initialise = initialise;
+ tool->finalise = finalise;
+ tool->w = ro_gui_dialog_create(tool->name);
+
+ /* create the icon */
+ new_icon.w = configure_window;
+ new_icon.icon.extent.x0 = 0;
+ new_icon.icon.extent.x1 = configure_icon_width;
+ new_icon.icon.extent.y1 = 0;
+ new_icon.icon.extent.y0 = -configure_icon_height;
+ new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE |
+ wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED |
+ (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT) |
+ (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
+ (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT);
+ new_icon.icon.data.indirected_text_and_sprite.text =
+ tool->translated;
+ new_icon.icon.data.indirected_text_and_sprite.validation =
+ tool->validation;
+ new_icon.icon.data.indirected_text_and_sprite.size =
+ CONFIGURE_TOOL_TRANSLATED_SIZE;
+ error = xwimp_create_icon(&new_icon, &tool->i);
+ if (error) {
+ LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ die(error->errmess);
+ }
+
+ /* Set the icon's text in current local encoding */
+ ro_gui_set_icon_string(configure_window, tool->i,
+ messages_get(tool->name), true);
+
+ /* link into our list alphabetically */
+ if ((!configure_tools) ||
+ (strcmp(configure_tools->translated,
+ tool->translated) > 0)) {
+ tool->next = configure_tools;
+ configure_tools = tool;
+ } else {
+ for (link = configure_tools; link; link = link->next) {
+ if (link->next) {
+ if (strcmp(link->next->translated,
+ tool->translated) > 0) {
+ tool->next = link->next;
+ link->next = tool;
+ break;
+ }
+ } else {
+ link->next = tool;
+ break;
+ }
+ }
+ }
+ configure_icons++;
+}
+
+/**
+ * Translate tool icons into the system local encoding.
+ * This will also recalculate the minimum required icon width.
+ *
+ * \return true on success, false on memory exhaustion
+ */
+bool ro_gui_configure_translate(void)
+{
+ int alphabet;
+ struct configure_tool *tool;
+ int icon_width;
+ os_error *error;
+
+ /* read current alphabet */
+ error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0,
+ &alphabet);
+ if (error) {
+ LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess);
+ /* assume Latin1 */
+ alphabet = territory_ALPHABET_LATIN1;
+ }
+
+ if (alphabet == configure_current_encoding)
+ /* text is already in the correct encoding */
+ return true;
+
+ /* reset icon width */
+ configure_icon_width = CONFIGURE_DEFAULT_ICON_WIDTH;
+
+ for (tool = configure_tools; tool; tool = tool->next) {
+ /* re-translate the text */
+ ro_gui_set_icon_string(configure_window, tool->i,
+ messages_get(tool->name), true);
+
+ /* update the width */
+ error = xwimptextop_string_width(tool->translated,
+ strlen(tool->translated), &icon_width);
+ if (error) {
+ LOG("xwimptextop_string_width: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+ icon_width += CONFIGURE_ICON_PADDING_H;
+ if (icon_width > configure_icon_width)
+ configure_icon_width = icon_width;
+
+ error = xwimp_resize_icon(configure_window,
+ tool->i,
+ 0,
+ -configure_icon_height,
+ configure_icon_width,
+ 0);
+ if (error) {
+ LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ }
+ }
+
+ /* invalidate our global icons_per_line setting
+ * so the icons get reflowed */
+ configure_icons_per_line = 0;
+
+ /* finally, set the current encoding */
+ configure_current_encoding = alphabet;
+
+ return true;
+}
diff --git a/frontends/riscos/configure.h b/frontends/riscos/configure.h
new file mode 100644
index 000000000..c190a6d0c
--- /dev/null
+++ b/frontends/riscos/configure.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * RISC OS option setting (interface).
+ */
+
+
+#ifndef _NETSURF_RISCOS_CONFIGURE_H_
+#define _NETSURF_RISCOS_CONFIGURE_H_
+
+#include <stdbool.h>
+#include "oslib/os.h"
+#include "oslib/wimp.h"
+
+void ro_gui_configure_initialise(void);
+void ro_gui_configure_show(void);
+
+#endif
diff --git a/frontends/riscos/configure/con_cache.c b/frontends/riscos/configure/con_cache.c
new file mode 100644
index 000000000..730d6f82f
--- /dev/null
+++ b/frontends/riscos/configure/con_cache.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <oslib/hourglass.h>
+
+#include "utils/nsoption.h"
+#include "utils/filename.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+
+#define CACHE_MEMORY_SIZE 3
+#define CACHE_MEMORY_DEC 4
+#define CACHE_MEMORY_INC 5
+#define CACHE_DISC_SIZE 10
+#define CACHE_DISC_DEC 11
+#define CACHE_DISC_INC 12
+#define CACHE_DISC_EXPIRE 15
+#define CACHE_DISC_EXPIRE_DEC 16
+#define CACHE_DISC_EXPIRE_INC 17
+#define CACHE_DEFAULT_BUTTON 19
+#define CACHE_CANCEL_BUTTON 20
+#define CACHE_OK_BUTTON 21
+
+static bool ro_gui_options_cache_click(wimp_pointer *pointer);
+static bool ro_gui_options_cache_ok(wimp_w w);
+
+bool ro_gui_options_cache_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_decimal(w, CACHE_MEMORY_SIZE,
+ (nsoption_int(memory_cache_size) * 10) >> 20, 1);
+ ro_gui_set_icon_decimal(w, CACHE_DISC_SIZE,
+ (int) ((nsoption_uint(disc_cache_size)) >> 20), 0);
+ ro_gui_set_icon_decimal(w, CACHE_DISC_EXPIRE,
+ (nsoption_int(disc_cache_age)), 0);
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_numeric_field(w, CACHE_MEMORY_SIZE,
+ CACHE_MEMORY_INC, CACHE_MEMORY_DEC, 0, 640, 1, 1);
+ ro_gui_wimp_event_register_numeric_field(w, CACHE_DISC_SIZE,
+ CACHE_DISC_INC, CACHE_DISC_DEC, 0, 4095, 1, 0);
+ ro_gui_wimp_event_register_numeric_field(w, CACHE_DISC_EXPIRE,
+ CACHE_DISC_EXPIRE_INC, CACHE_DISC_EXPIRE_DEC, 1, 3650,
+ 1, 0);
+ ro_gui_wimp_event_register_mouse_click(w, ro_gui_options_cache_click);
+ ro_gui_wimp_event_register_cancel(w, CACHE_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, CACHE_OK_BUTTON,
+ ro_gui_options_cache_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpCacheConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+bool ro_gui_options_cache_click(wimp_pointer *pointer)
+{
+ switch (pointer->i) {
+ case CACHE_DEFAULT_BUTTON:
+ /* set the default values */
+ ro_gui_set_icon_decimal(pointer->w, CACHE_MEMORY_SIZE,
+ 120, 1);
+ ro_gui_set_icon_decimal(pointer->w, CACHE_DISC_SIZE,
+ 1024, 0);
+ ro_gui_set_icon_decimal(pointer->w, CACHE_DISC_EXPIRE,
+ 28, 0);
+ return true;
+ }
+ return false;
+}
+
+bool ro_gui_options_cache_ok(wimp_w w)
+{
+ nsoption_set_int(memory_cache_size,
+ (((ro_gui_get_icon_decimal(w,
+ CACHE_MEMORY_SIZE, 1) + 1) << 20) - 1) / 10);
+ nsoption_set_uint(disc_cache_size,
+ (uint) (ro_gui_get_icon_decimal(w,
+ CACHE_DISC_SIZE, 0) << 20));
+ nsoption_set_int(disc_cache_age,
+ ro_gui_get_icon_decimal(w, CACHE_DISC_EXPIRE, 0));
+
+ ro_gui_save_options();
+ return true;
+}
diff --git a/frontends/riscos/configure/con_connect.c b/frontends/riscos/configure/con_connect.c
new file mode 100644
index 000000000..9515c5d6f
--- /dev/null
+++ b/frontends/riscos/configure/con_connect.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include "swis.h"
+#include "oslib/osspriteop.h"
+#include "oslib/wimp.h"
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+#include "riscos/menus.h"
+#include "riscos/tinct.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+
+
+#define CONNECTION_PROXY_FIELD 3
+#define CONNECTION_PROXY_MENU 4
+#define CONNECTION_PROXY_HOST_LABEL 5
+#define CONNECTION_PROXY_HOST 6
+#define CONNECTION_PROXY_PORT_LABEL 7
+#define CONNECTION_PROXY_PORT 8
+#define CONNECTION_PROXY_USERNAME_LABEL 9
+#define CONNECTION_PROXY_USERNAME 10
+#define CONNECTION_PROXY_PASSWORD_LABEL 11
+#define CONNECTION_PROXY_PASSWORD 12
+#define CONNECTION_MAX_FETCH_FIELD 16
+#define CONNECTION_MAX_FETCH_DEC 17
+#define CONNECTION_MAX_FETCH_INC 18
+#define CONNECTION_HOST_FETCH_FIELD 20
+#define CONNECTION_HOST_FETCH_DEC 21
+#define CONNECTION_HOST_FETCH_INC 22
+#define CONNECTION_CACHE_FETCH_FIELD 24
+#define CONNECTION_CACHE_FETCH_DEC 25
+#define CONNECTION_CACHE_FETCH_INC 26
+#define CONNECTION_DEFAULT_BUTTON 27
+#define CONNECTION_CANCEL_BUTTON 28
+#define CONNECTION_OK_BUTTON 29
+
+#define http_proxy_type (nsoption_bool(http_proxy) ? (nsoption_int(http_proxy_auth) + 1) : 0)
+
+static int ro_gui_options_connection_proxy_type(wimp_w w);
+static void ro_gui_options_connection_default(wimp_pointer *pointer);
+static bool ro_gui_options_connection_ok(wimp_w w);
+static bool ro_gui_options_connection_update(wimp_w w, wimp_i i, wimp_menu *m,
+ wimp_selection *s, menu_action a);
+
+bool ro_gui_options_connection_initialise(wimp_w w)
+{
+ int proxy_type;
+
+ /* set the current values */
+ proxy_type = (nsoption_bool(http_proxy) ? (nsoption_int(http_proxy_auth) + 1) : 0);
+ ro_gui_set_icon_string(w, CONNECTION_PROXY_FIELD,
+ proxy_type_menu->entries[proxy_type].
+ data.indirected_text.text, true);
+ ro_gui_set_icon_string(w, CONNECTION_PROXY_HOST,
+ nsoption_charp(http_proxy_host) ?
+ nsoption_charp(http_proxy_host) : "", true);
+ ro_gui_set_icon_integer(w, CONNECTION_PROXY_PORT,
+ nsoption_int(http_proxy_port));
+ ro_gui_set_icon_string(w, CONNECTION_PROXY_USERNAME,
+ nsoption_charp(http_proxy_auth_user) ?
+ nsoption_charp(http_proxy_auth_user) : "", true);
+ ro_gui_set_icon_string(w, CONNECTION_PROXY_PASSWORD,
+ nsoption_charp(http_proxy_auth_pass) ?
+ nsoption_charp(http_proxy_auth_pass) : "", true);
+ ro_gui_set_icon_integer(w, CONNECTION_MAX_FETCH_FIELD,
+ nsoption_int(max_fetchers));
+ ro_gui_set_icon_integer(w, CONNECTION_HOST_FETCH_FIELD,
+ nsoption_int(max_fetchers_per_host));
+ ro_gui_set_icon_integer(w, CONNECTION_CACHE_FETCH_FIELD,
+ nsoption_int(max_cached_fetch_handles));
+ ro_gui_options_connection_update(w, -1, NULL, NULL, NO_ACTION);
+
+ /* register icons */
+ ro_gui_wimp_event_register_menu_gright(w, CONNECTION_PROXY_FIELD,
+ CONNECTION_PROXY_MENU, proxy_type_menu);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_HOST_LABEL);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_HOST);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_PORT_LABEL);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_PORT);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_USERNAME_LABEL);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_USERNAME);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_PASSWORD_LABEL);
+ ro_gui_wimp_event_register_text_field(w, CONNECTION_PROXY_PASSWORD);
+ ro_gui_wimp_event_register_numeric_field(w, CONNECTION_MAX_FETCH_FIELD,
+ CONNECTION_MAX_FETCH_INC, CONNECTION_MAX_FETCH_DEC,
+ 1, 99, 1, 0);
+ ro_gui_wimp_event_register_numeric_field(w, CONNECTION_HOST_FETCH_FIELD,
+ CONNECTION_HOST_FETCH_INC, CONNECTION_HOST_FETCH_DEC,
+ 1, 99, 1, 0);
+ ro_gui_wimp_event_register_numeric_field(w, CONNECTION_CACHE_FETCH_FIELD,
+ CONNECTION_CACHE_FETCH_INC, CONNECTION_CACHE_FETCH_DEC,
+ 1, 99, 1, 0);
+ ro_gui_wimp_event_register_menu_selection(w,
+ ro_gui_options_connection_update);
+ ro_gui_wimp_event_register_button(w, CONNECTION_DEFAULT_BUTTON,
+ ro_gui_options_connection_default);
+ ro_gui_wimp_event_register_cancel(w, CONNECTION_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, CONNECTION_OK_BUTTON,
+ ro_gui_options_connection_ok);
+
+ ro_gui_wimp_event_set_help_prefix(w, "HelpConnectConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+bool ro_gui_options_connection_update(wimp_w w, wimp_i i, wimp_menu *m,
+ wimp_selection *s, menu_action a)
+{
+ int proxy_type;
+ bool host, user;
+
+ /* update the shaded state */
+ proxy_type = ro_gui_options_connection_proxy_type(w);
+ host = (proxy_type > 0);
+ user = (proxy_type > 1);
+
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_HOST_LABEL, !host);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_HOST, !host);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_PORT_LABEL, !host);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_PORT, !host);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_USERNAME_LABEL, !user);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_USERNAME, !user);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_PASSWORD_LABEL, !user);
+ ro_gui_set_icon_shaded_state(w, CONNECTION_PROXY_PASSWORD, !user);
+
+ return true;
+}
+
+int ro_gui_options_connection_proxy_type(wimp_w w)
+{
+ const char *text;
+ int i;
+
+ text = ro_gui_get_icon_string(w, CONNECTION_PROXY_FIELD);
+ for (i = 0; (i < 4); i++)
+ if (!strcmp(text, proxy_type_menu->entries[i].
+ data.indirected_text.text))
+ return i;
+ assert(false);
+}
+
+void ro_gui_options_connection_default(wimp_pointer *pointer)
+{
+ ro_gui_set_icon_string(pointer->w, CONNECTION_PROXY_FIELD,
+ proxy_type_menu->entries[0].
+ data.indirected_text.text, true);
+ ro_gui_set_icon_string(pointer->w, CONNECTION_PROXY_HOST, "", true);
+ ro_gui_set_icon_integer(pointer->w, CONNECTION_PROXY_PORT, 8080);
+ ro_gui_set_icon_string(pointer->w, CONNECTION_PROXY_USERNAME, "", true);
+ ro_gui_set_icon_string(pointer->w, CONNECTION_PROXY_PASSWORD, "", true);
+ ro_gui_set_icon_integer(pointer->w, CONNECTION_MAX_FETCH_FIELD, 24);
+ ro_gui_set_icon_integer(pointer->w, CONNECTION_HOST_FETCH_FIELD, 5);
+ ro_gui_set_icon_integer(pointer->w, CONNECTION_CACHE_FETCH_FIELD, 6);
+ ro_gui_options_connection_update(pointer->w, -1, NULL, NULL, NO_ACTION);
+}
+
+bool ro_gui_options_connection_ok(wimp_w w)
+{
+ int proxy_type;
+
+ proxy_type = ro_gui_options_connection_proxy_type(w);
+ if (proxy_type == 0) {
+ nsoption_set_bool(http_proxy, false);
+ } else {
+ nsoption_set_bool(http_proxy, true);
+ nsoption_set_int(http_proxy_auth, proxy_type - 1);
+ }
+
+ nsoption_set_charp(http_proxy_host,
+ strdup(ro_gui_get_icon_string(w,
+ CONNECTION_PROXY_HOST)));
+
+ nsoption_set_int(http_proxy_port,
+ ro_gui_get_icon_decimal(w, CONNECTION_PROXY_PORT, 0));
+
+ nsoption_set_charp(http_proxy_auth_user,
+ strdup(ro_gui_get_icon_string(w,
+ CONNECTION_PROXY_USERNAME)));
+
+ nsoption_set_charp(http_proxy_auth_pass,
+ strdup(ro_gui_get_icon_string(w,
+ CONNECTION_PROXY_PASSWORD)));
+
+ nsoption_set_int(max_fetchers,
+ ro_gui_get_icon_decimal(w,
+ CONNECTION_MAX_FETCH_FIELD, 0));
+
+ nsoption_set_int(max_fetchers_per_host,
+ ro_gui_get_icon_decimal(w,
+ CONNECTION_HOST_FETCH_FIELD, 0));
+
+ nsoption_set_int(max_cached_fetch_handles,
+ ro_gui_get_icon_decimal(w,
+ CONNECTION_CACHE_FETCH_FIELD, 0));
+
+ ro_gui_save_options();
+ return true;
+}
diff --git a/frontends/riscos/configure/con_content.c b/frontends/riscos/configure/con_content.c
new file mode 100644
index 000000000..50bbd15ef
--- /dev/null
+++ b/frontends/riscos/configure/con_content.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+#define CONTENT_BLOCK_ADVERTISEMENTS 2
+#define CONTENT_BLOCK_POPUPS 3
+#define CONTENT_NO_PLUGINS 4
+#define CONTENT_TARGET_BLANK 7
+#define CONTENT_DEFAULT_BUTTON 8
+#define CONTENT_CANCEL_BUTTON 9
+#define CONTENT_OK_BUTTON 10
+#define CONTENT_NO_JAVASCRIPT 11
+
+static void ro_gui_options_content_default(wimp_pointer *pointer);
+static bool ro_gui_options_content_ok(wimp_w w);
+
+bool ro_gui_options_content_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_selected_state(w, CONTENT_BLOCK_ADVERTISEMENTS,
+ nsoption_bool(block_advertisements));
+ ro_gui_set_icon_selected_state(w, CONTENT_BLOCK_POPUPS,
+ nsoption_bool(block_popups));
+ ro_gui_set_icon_selected_state(w, CONTENT_NO_PLUGINS,
+ nsoption_bool(no_plugins));
+ ro_gui_set_icon_selected_state(w, CONTENT_TARGET_BLANK,
+ nsoption_bool(target_blank));
+ ro_gui_set_icon_selected_state(w, CONTENT_NO_JAVASCRIPT,
+ !nsoption_bool(enable_javascript));
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_checkbox(w, CONTENT_BLOCK_ADVERTISEMENTS);
+ ro_gui_wimp_event_register_checkbox(w, CONTENT_BLOCK_POPUPS);
+ ro_gui_wimp_event_register_checkbox(w, CONTENT_NO_PLUGINS);
+ ro_gui_wimp_event_register_checkbox(w, CONTENT_TARGET_BLANK);
+ ro_gui_wimp_event_register_checkbox(w, CONTENT_NO_JAVASCRIPT);
+ ro_gui_wimp_event_register_button(w, CONTENT_DEFAULT_BUTTON,
+ ro_gui_options_content_default);
+ ro_gui_wimp_event_register_cancel(w, CONTENT_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, CONTENT_OK_BUTTON,
+ ro_gui_options_content_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpContentConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+void ro_gui_options_content_default(wimp_pointer *pointer)
+{
+ /* set the default values */
+ ro_gui_set_icon_selected_state(pointer->w, CONTENT_BLOCK_ADVERTISEMENTS,
+ false);
+ ro_gui_set_icon_selected_state(pointer->w, CONTENT_BLOCK_POPUPS,
+ false);
+ ro_gui_set_icon_selected_state(pointer->w, CONTENT_NO_PLUGINS,
+ false);
+ ro_gui_set_icon_selected_state(pointer->w, CONTENT_TARGET_BLANK,
+ true);
+ ro_gui_set_icon_selected_state(pointer->w, CONTENT_NO_JAVASCRIPT,
+ false);
+}
+
+bool ro_gui_options_content_ok(wimp_w w)
+{
+ nsoption_set_bool(block_advertisements,
+ ro_gui_get_icon_selected_state(w, CONTENT_BLOCK_ADVERTISEMENTS));
+
+ nsoption_set_bool(block_popups,
+ ro_gui_get_icon_selected_state(w, CONTENT_BLOCK_POPUPS));
+ nsoption_set_bool(no_plugins,
+ ro_gui_get_icon_selected_state(w, CONTENT_NO_PLUGINS));
+
+ nsoption_set_bool(target_blank,
+ ro_gui_get_icon_selected_state(w, CONTENT_TARGET_BLANK));
+
+ nsoption_set_bool(enable_javascript,
+ !ro_gui_get_icon_selected_state(w, CONTENT_NO_JAVASCRIPT));
+
+ ro_gui_save_options();
+ return true;
+}
diff --git a/frontends/riscos/configure/con_fonts.c b/frontends/riscos/configure/con_fonts.c
new file mode 100644
index 000000000..280312843
--- /dev/null
+++ b/frontends/riscos/configure/con_fonts.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+#include "desktop/plot_style.h"
+
+#include "riscos/gui.h"
+#include "riscos/font.h"
+#include "riscos/menus.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+
+#define FONT_SANS_FIELD 3
+#define FONT_SANS_MENU 4
+#define FONT_SERIF_FIELD 6
+#define FONT_SERIF_MENU 7
+#define FONT_MONOSPACE_FIELD 9
+#define FONT_MONOSPACE_MENU 10
+#define FONT_CURSIVE_FIELD 12
+#define FONT_CURSIVE_MENU 13
+#define FONT_FANTASY_FIELD 15
+#define FONT_FANTASY_MENU 16
+#define FONT_DEFAULT_FIELD 18
+#define FONT_DEFAULT_MENU 19
+#define FONT_DEFAULT_SIZE 23
+#define FONT_DEFAULT_DEC 24
+#define FONT_DEFAULT_INC 25
+#define FONT_MINIMUM_SIZE 28
+#define FONT_MINIMUM_DEC 29
+#define FONT_MINIMUM_INC 30
+#define FONT_DEFAULT_BUTTON 32
+#define FONT_CANCEL_BUTTON 33
+#define FONT_OK_BUTTON 34
+
+/* This menu only ever gets created once */
+/** \todo The memory claimed for this menu should
+ * probably be released at some point */
+static wimp_menu *default_menu;
+
+static const char *font_names[PLOT_FONT_FAMILY_COUNT] = {
+ "Sans-serif",
+ "Serif",
+ "Monospace",
+ "Cursive",
+ "Fantasy"
+};
+
+static void ro_gui_options_fonts_default(wimp_pointer *pointer);
+static bool ro_gui_options_fonts_ok(wimp_w w);
+static bool ro_gui_options_fonts_init_menu(void);
+
+bool ro_gui_options_fonts_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_decimal(w, FONT_DEFAULT_SIZE, nsoption_int(font_size), 1);
+ ro_gui_set_icon_decimal(w, FONT_MINIMUM_SIZE, nsoption_int(font_min_size), 1);
+ ro_gui_set_icon_string(w, FONT_SANS_FIELD, nsoption_charp(font_sans), true);
+ ro_gui_set_icon_string(w, FONT_SERIF_FIELD, nsoption_charp(font_serif), true);
+ ro_gui_set_icon_string(w, FONT_MONOSPACE_FIELD, nsoption_charp(font_mono), true);
+ ro_gui_set_icon_string(w, FONT_CURSIVE_FIELD, nsoption_charp(font_cursive), true);
+ ro_gui_set_icon_string(w, FONT_FANTASY_FIELD, nsoption_charp(font_fantasy), true);
+ ro_gui_set_icon_string(w, FONT_DEFAULT_FIELD,
+ font_names[nsoption_int(font_default)], true);
+
+ if (!ro_gui_options_fonts_init_menu())
+ return false;
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_menu_gright(w, FONT_SANS_FIELD,
+ FONT_SANS_MENU, rufl_family_menu);
+ ro_gui_wimp_event_register_menu_gright(w, FONT_SERIF_FIELD,
+ FONT_SERIF_MENU, rufl_family_menu);
+ ro_gui_wimp_event_register_menu_gright(w, FONT_MONOSPACE_FIELD,
+ FONT_MONOSPACE_MENU, rufl_family_menu);
+ ro_gui_wimp_event_register_menu_gright(w, FONT_CURSIVE_FIELD,
+ FONT_CURSIVE_MENU, rufl_family_menu);
+ ro_gui_wimp_event_register_menu_gright(w, FONT_FANTASY_FIELD,
+ FONT_FANTASY_MENU, rufl_family_menu);
+ ro_gui_wimp_event_register_menu_gright(w, FONT_DEFAULT_FIELD,
+ FONT_DEFAULT_MENU, default_menu);
+ ro_gui_wimp_event_register_numeric_field(w, FONT_DEFAULT_SIZE,
+ FONT_DEFAULT_INC, FONT_DEFAULT_DEC, 50, 1000, 1, 1);
+ ro_gui_wimp_event_register_numeric_field(w, FONT_MINIMUM_SIZE,
+ FONT_MINIMUM_INC, FONT_MINIMUM_DEC, 10, 500, 1, 1);
+ ro_gui_wimp_event_register_button(w, FONT_DEFAULT_BUTTON,
+ ro_gui_options_fonts_default);
+ ro_gui_wimp_event_register_cancel(w, FONT_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, FONT_OK_BUTTON,
+ ro_gui_options_fonts_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpFontConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+void ro_gui_options_fonts_default(wimp_pointer *pointer)
+{
+ const char *fallback = nsfont_fallback_font();
+
+ /* set the default values */
+ ro_gui_set_icon_decimal(pointer->w, FONT_DEFAULT_SIZE, 128, 1);
+ ro_gui_set_icon_decimal(pointer->w, FONT_MINIMUM_SIZE, 85, 1);
+ ro_gui_set_icon_string(pointer->w, FONT_SANS_FIELD,
+ nsfont_exists("Homerton") ? "Homerton" : fallback, true);
+ ro_gui_set_icon_string(pointer->w, FONT_SERIF_FIELD,
+ nsfont_exists("Trinity") ? "Trinity" : fallback, true);
+ ro_gui_set_icon_string(pointer->w, FONT_MONOSPACE_FIELD,
+ nsfont_exists("Corpus") ? "Corpus" : fallback, true);
+ ro_gui_set_icon_string(pointer->w, FONT_CURSIVE_FIELD,
+ nsfont_exists("Churchill") ? "Churchill" : fallback, true);
+ ro_gui_set_icon_string(pointer->w, FONT_FANTASY_FIELD,
+ nsfont_exists("Sassoon") ? "Sassoon" : fallback, true);
+ ro_gui_set_icon_string(pointer->w, FONT_DEFAULT_FIELD,
+ font_names[0], true);
+}
+
+bool ro_gui_options_fonts_ok(wimp_w w)
+{
+ unsigned int i;
+
+ nsoption_set_int(font_size,
+ ro_gui_get_icon_decimal(w, FONT_DEFAULT_SIZE, 1));
+
+ nsoption_set_int(font_min_size,
+ ro_gui_get_icon_decimal(w, FONT_MINIMUM_SIZE, 1));
+
+ if (nsoption_int(font_size) < nsoption_int(font_min_size)) {
+ nsoption_set_int(font_size, nsoption_int(font_min_size));
+ ro_gui_set_icon_decimal(w, FONT_DEFAULT_SIZE, nsoption_int(font_size), 1);
+
+}
+
+ nsoption_set_charp(font_sans,
+ strdup(ro_gui_get_icon_string(w, FONT_SANS_FIELD)));
+
+ nsoption_set_charp(font_serif,
+ strdup(ro_gui_get_icon_string(w, FONT_SERIF_FIELD)));
+
+ nsoption_set_charp(font_mono,
+ strdup(ro_gui_get_icon_string(w, FONT_MONOSPACE_FIELD)));
+
+ nsoption_set_charp(font_cursive,
+ strdup(ro_gui_get_icon_string(w, FONT_CURSIVE_FIELD)));
+
+ nsoption_set_charp(font_fantasy,
+ strdup(ro_gui_get_icon_string(w, FONT_FANTASY_FIELD)));
+
+ for (i = 0; i != 5; i++) {
+ if (!strcmp(font_names[i], ro_gui_get_icon_string(w,
+ FONT_DEFAULT_FIELD)))
+ break;
+ }
+ if (i == 5)
+ /* this should never happen, but still */
+ i = 0;
+
+ nsoption_set_int(font_default, i);
+
+ ro_gui_save_options();
+ return true;
+}
+
+bool ro_gui_options_fonts_init_menu(void)
+{
+ unsigned int i;
+
+ if (default_menu)
+ /* Already exists */
+ return true;
+
+ default_menu = malloc(wimp_SIZEOF_MENU(5));
+ if (!default_menu) {
+ ro_warn_user("NoMemory", 0);
+ return false;
+ }
+ default_menu->title_data.indirected_text.text =
+ (char *) messages_get("DefaultFonts");
+ ro_gui_menu_init_structure(default_menu, 5);
+ for (i = 0; i < 5; i++) {
+ default_menu->entries[i].data.indirected_text.text =
+ (char *) font_names[i];
+ default_menu->entries[i].data.indirected_text.size =
+ strlen(font_names[i]);
+ }
+ return true;
+}
diff --git a/frontends/riscos/configure/con_home.c b/frontends/riscos/configure/con_home.c
new file mode 100644
index 000000000..ea8e243ed
--- /dev/null
+++ b/frontends/riscos/configure/con_home.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+
+#include "riscos/gui.h"
+#include "riscos/menus.h"
+#include "riscos/url_suggest.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+#define HOME_URL_FIELD 3
+#define HOME_URL_GRIGHT 4
+#define HOME_OPEN_STARTUP 5
+#define HOME_DEFAULT_BUTTON 6
+#define HOME_CANCEL_BUTTON 7
+#define HOME_OK_BUTTON 8
+
+static void ro_gui_options_home_default(wimp_pointer *pointer);
+static bool ro_gui_options_home_ok(wimp_w w);
+static bool ro_gui_options_home_menu_prepare(wimp_w w, wimp_i i,
+ wimp_menu *menu, wimp_pointer *pointer);
+
+bool ro_gui_options_home_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_string(w, HOME_URL_FIELD,
+ nsoption_charp(homepage_url) ?
+ nsoption_charp(homepage_url) : "", true);
+
+ ro_gui_set_icon_selected_state(w, HOME_OPEN_STARTUP,
+ nsoption_bool(open_browser_at_startup));
+
+ ro_gui_set_icon_shaded_state(w,
+ HOME_URL_GRIGHT, !ro_gui_url_suggest_prepare_menu());
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_menu_gright(w, HOME_URL_FIELD,
+ HOME_URL_GRIGHT, ro_gui_url_suggest_menu);
+ ro_gui_wimp_event_register_checkbox(w, HOME_OPEN_STARTUP);
+ ro_gui_wimp_event_register_button(w, HOME_DEFAULT_BUTTON,
+ ro_gui_options_home_default);
+ ro_gui_wimp_event_register_cancel(w, HOME_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, HOME_OK_BUTTON,
+ ro_gui_options_home_ok);
+ ro_gui_wimp_event_register_menu_prepare(w,
+ ro_gui_options_home_menu_prepare);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpHomeConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+void ro_gui_options_home_default(wimp_pointer *pointer)
+{
+ /* set the default values */
+ ro_gui_set_icon_string(pointer->w, HOME_URL_FIELD, "", true);
+ ro_gui_set_icon_selected_state(pointer->w, HOME_OPEN_STARTUP, false);
+}
+
+bool ro_gui_options_home_ok(wimp_w w)
+{
+ nsoption_set_charp(homepage_url,
+ strdup(ro_gui_get_icon_string(w, HOME_URL_FIELD)));
+
+ nsoption_set_bool(open_browser_at_startup,
+ ro_gui_get_icon_selected_state(w, HOME_OPEN_STARTUP));
+
+ ro_gui_save_options();
+ return true;
+}
+
+
+/**
+ * Callback to prepare menus in the Configure Home dialog. At present, this
+ * only has to handle the URL Suggestion pop-up.
+ *
+ * \param w The window handle owning the menu.
+ * \param i The icon handle owning the menu.
+ * \param *menu The menu to be prepared.
+ * \param *pointer The associated mouse click event block, or NULL
+ * on an Adjust-click re-opening.
+ * \return true if the event was handled; false if not.
+ */
+
+bool ro_gui_options_home_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_pointer *pointer)
+{
+ if (menu != ro_gui_url_suggest_menu || i != HOME_URL_GRIGHT)
+ return false;
+
+ if (pointer != NULL)
+ ro_gui_url_suggest_prepare_menu();
+
+ return true;
+}
diff --git a/frontends/riscos/configure/con_image.c b/frontends/riscos/configure/con_image.c
new file mode 100644
index 000000000..49dd4f76d
--- /dev/null
+++ b/frontends/riscos/configure/con_image.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <swis.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+
+#include "riscos/gui.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+#include "riscos/menus.h"
+#include "riscos/tinct.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+
+
+#define IMAGE_FOREGROUND_FIELD 3
+#define IMAGE_FOREGROUND_MENU 4
+#define IMAGE_BACKGROUND_FIELD 6
+#define IMAGE_BACKGROUND_MENU 7
+#define IMAGE_CURRENT_DISPLAY 8
+#define IMAGE_SPEED_TEXT 11
+#define IMAGE_SPEED_FIELD 12
+#define IMAGE_SPEED_DEC 13
+#define IMAGE_SPEED_INC 14
+#define IMAGE_SPEED_CS 15
+#define IMAGE_DISABLE_ANIMATION 16
+#define IMAGE_DEFAULT_BUTTON 17
+#define IMAGE_CANCEL_BUTTON 18
+#define IMAGE_OK_BUTTON 19
+
+static bool ro_gui_options_image_click(wimp_pointer *pointer);
+static bool ro_gui_options_image_ok(wimp_w w);
+static void ro_gui_options_image_redraw(wimp_draw *redraw);
+static bool ro_gui_options_image_update(wimp_w w, wimp_i i, wimp_menu *m,
+ wimp_selection *s, menu_action a);
+static void ro_gui_options_image_read(wimp_w w, unsigned int *bg,
+ unsigned int *fg);
+static void ro_gui_options_update_shading(wimp_w w);
+
+static osspriteop_area *example_images;
+int example_users = 0;
+unsigned int tinct_options[] = {tinct_USE_OS_SPRITE_OP, 0, tinct_DITHER,
+ tinct_ERROR_DIFFUSE};
+
+bool ro_gui_options_image_initialise(wimp_w w)
+{
+ int i;
+
+ /* load the sprite file */
+ if (example_users == 0) {
+ char pathname[256];
+ snprintf(pathname, 256, "%s.Resources.Image", NETSURF_DIR);
+ pathname[255] = '\0';
+ example_images = ro_gui_load_sprite_file(pathname);
+ if (!example_images)
+ return false;
+ }
+ example_users++;
+
+ /* set the current values */
+ for (i = 0; (i < 4); i++) {
+ if ((unsigned int)nsoption_int(plot_fg_quality) == tinct_options[i])
+ ro_gui_set_icon_string(w, IMAGE_FOREGROUND_FIELD,
+ image_quality_menu->entries[i].
+ data.indirected_text.text, true);
+ if ((unsigned int)nsoption_int(plot_bg_quality) == tinct_options[i])
+ ro_gui_set_icon_string(w, IMAGE_BACKGROUND_FIELD,
+ image_quality_menu->entries[i].
+ data.indirected_text.text, true);
+ }
+ ro_gui_set_icon_decimal(w, IMAGE_SPEED_FIELD,
+ nsoption_int(minimum_gif_delay), 2);
+ ro_gui_set_icon_selected_state(w, IMAGE_DISABLE_ANIMATION,
+ !nsoption_bool(animate_images));
+ ro_gui_options_update_shading(w);
+
+ /* register icons */
+ ro_gui_wimp_event_register_menu_gright(w, IMAGE_FOREGROUND_FIELD,
+ IMAGE_FOREGROUND_MENU, image_quality_menu);
+ ro_gui_wimp_event_register_menu_gright(w, IMAGE_BACKGROUND_FIELD,
+ IMAGE_BACKGROUND_MENU, image_quality_menu);
+ ro_gui_wimp_event_register_text_field(w, IMAGE_SPEED_TEXT);
+ ro_gui_wimp_event_register_numeric_field(w, IMAGE_SPEED_FIELD,
+ IMAGE_SPEED_INC, IMAGE_SPEED_DEC, 0, 6000, 10, 2);
+ ro_gui_wimp_event_register_checkbox(w, IMAGE_DISABLE_ANIMATION);
+ ro_gui_wimp_event_register_text_field(w, IMAGE_SPEED_CS);
+ ro_gui_wimp_event_register_redraw_window(w,
+ ro_gui_options_image_redraw);
+ ro_gui_wimp_event_register_mouse_click(w,
+ ro_gui_options_image_click);
+ ro_gui_wimp_event_register_menu_selection(w,
+ ro_gui_options_image_update);
+ ro_gui_wimp_event_register_cancel(w, IMAGE_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, IMAGE_OK_BUTTON,
+ ro_gui_options_image_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpImageConfig");
+ ro_gui_wimp_event_memorise(w);
+
+ return true;
+}
+
+void ro_gui_options_image_finalise(wimp_w w)
+{
+ example_users--;
+ if (example_users == 0) {
+ free(example_images);
+ example_images = NULL;
+ }
+ ro_gui_wimp_event_finalise(w);
+}
+
+bool ro_gui_options_image_update(wimp_w w, wimp_i i, wimp_menu *m,
+ wimp_selection *s, menu_action a)
+{
+ ro_gui_redraw_icon(w, IMAGE_CURRENT_DISPLAY);
+
+ return true;
+}
+
+void ro_gui_options_image_redraw(wimp_draw *redraw)
+{
+ osbool more;
+ os_error *error;
+ wimp_icon_state icon_state;
+ osspriteop_header *bg = NULL, *fg = NULL;
+ unsigned int bg_tinct = 0, fg_tinct = 0;
+
+ /* get the icon location */
+ icon_state.w = redraw->w;
+ icon_state.i = IMAGE_CURRENT_DISPLAY;
+ error = xwimp_get_icon_state(&icon_state);
+ if (error) {
+ LOG("xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("MenuError", error->errmess);
+ return;
+ }
+
+ /* find the sprites */
+ if (example_images) {
+ ro_gui_options_image_read(redraw->w, &bg_tinct, &fg_tinct);
+ fg_tinct |= 0xeeeeee00;
+ xosspriteop_select_sprite(osspriteop_USER_AREA,
+ example_images, (osspriteop_id)"img_bg", &bg);
+ xosspriteop_select_sprite(osspriteop_USER_AREA,
+ example_images, (osspriteop_id)"img_fg", &fg);
+ }
+
+ /* perform the redraw */
+ more = wimp_redraw_window(redraw);
+ while (more) {
+ int origin_x, origin_y;
+ origin_x = redraw->box.x0 - redraw->xscroll +
+ icon_state.icon.extent.x0 + 2;
+ origin_y = redraw->box.y1 - redraw->yscroll +
+ icon_state.icon.extent.y0 + 2;
+ if (bg)
+ _swix(Tinct_Plot, _INR(2,4) | _IN(7),
+ bg, origin_x, origin_y, bg_tinct);
+ if (fg)
+ _swix(Tinct_PlotAlpha, _INR(2,4) | _IN(7),
+ fg, origin_x, origin_y, fg_tinct);
+ more = wimp_get_rectangle(redraw);
+ }
+}
+
+void ro_gui_options_image_read(wimp_w w, unsigned int *bg, unsigned int *fg)
+{
+ const char *text;
+ int i;
+
+ text = ro_gui_get_icon_string(w, IMAGE_FOREGROUND_FIELD);
+ for (i = 0; i < 4; i++)
+ if (!strcmp(text, image_quality_menu->entries[i].
+ data.indirected_text.text))
+ *fg = tinct_options[i];
+
+ text = ro_gui_get_icon_string(w, IMAGE_BACKGROUND_FIELD);
+ for (i = 0; i < 4; i++)
+ if (!strcmp(text, image_quality_menu->entries[i].
+ data.indirected_text.text))
+ *bg = tinct_options[i];
+}
+
+bool ro_gui_options_image_click(wimp_pointer *pointer)
+{
+ unsigned int old_fg, old_bg, bg, fg;
+
+ ro_gui_options_image_read(pointer->w, &old_bg, &old_fg);
+ switch (pointer->i) {
+ case IMAGE_DEFAULT_BUTTON:
+ ro_gui_set_icon_string(pointer->w,
+ IMAGE_FOREGROUND_FIELD,
+ image_quality_menu->entries[3].
+ data.indirected_text.text, true);
+ ro_gui_set_icon_string(pointer->w,
+ IMAGE_BACKGROUND_FIELD,
+ image_quality_menu->entries[2].
+ data.indirected_text.text, true);
+ ro_gui_set_icon_decimal(pointer->w, IMAGE_SPEED_FIELD,
+ 10, 2);
+ ro_gui_set_icon_selected_state(pointer->w,
+ IMAGE_DISABLE_ANIMATION, false);
+ case IMAGE_DISABLE_ANIMATION:
+ ro_gui_options_update_shading(pointer->w);
+ break;
+ case IMAGE_CANCEL_BUTTON:
+ ro_gui_wimp_event_restore(pointer->w);
+ break;
+ default:
+ return false;
+ }
+
+ ro_gui_options_image_read(pointer->w, &bg, &fg);
+ if ((bg != old_bg) || (fg != old_fg))
+ ro_gui_options_image_update(pointer->w, pointer->i,
+ NULL, NULL, NO_ACTION);
+
+ return false;
+}
+
+void ro_gui_options_update_shading(wimp_w w)
+{
+ bool shaded;
+
+ shaded = ro_gui_get_icon_selected_state(w, IMAGE_DISABLE_ANIMATION);
+ ro_gui_set_icon_shaded_state(w, IMAGE_SPEED_TEXT, shaded);
+ ro_gui_set_icon_shaded_state(w, IMAGE_SPEED_FIELD, shaded);
+ ro_gui_set_icon_shaded_state(w, IMAGE_SPEED_DEC, shaded);
+ ro_gui_set_icon_shaded_state(w, IMAGE_SPEED_INC, shaded);
+ ro_gui_set_icon_shaded_state(w, IMAGE_SPEED_CS, shaded);
+}
+
+bool ro_gui_options_image_ok(wimp_w w)
+{
+ ro_gui_options_image_read(w,
+ (unsigned int *)&nsoption_int(plot_bg_quality),
+ (unsigned int *)&nsoption_int(plot_fg_quality));
+
+ nsoption_set_int(minimum_gif_delay,
+ ro_gui_get_icon_decimal(w, IMAGE_SPEED_FIELD, 2));
+
+ nsoption_set_bool(animate_images,
+ !ro_gui_get_icon_selected_state(w,
+ IMAGE_DISABLE_ANIMATION));
+ ro_gui_save_options();
+
+ return true;
+}
diff --git a/frontends/riscos/configure/con_inter.c b/frontends/riscos/configure/con_inter.c
new file mode 100644
index 000000000..7ab912c54
--- /dev/null
+++ b/frontends/riscos/configure/con_inter.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+
+#include "utils/nsoption.h"
+
+#include "riscos/gui.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+#define INTERFACE_STRIP_EXTNS_OPTION 2
+#define INTERFACE_CONFIRM_OVWR_OPTION 3
+#define INTERFACE_URL_COMPLETE_OPTION 6
+#define INTERFACE_HISTORY_TOOLTIP_OPTION 7
+#define INTERFACE_THUMBNAIL_ICONISE_OPTION 10
+#define INTERFACE_DEFAULT_BUTTON 11
+#define INTERFACE_CANCEL_BUTTON 12
+#define INTERFACE_OK_BUTTON 13
+#define INTERFACE_USE_EXTERNAL_HOTLIST 16
+#define INTERFACE_EXTERNAL_HOTLIST_APP 18
+
+
+static bool ro_gui_options_interface_click(wimp_pointer *pointer);
+static void ro_gui_options_interface_default(wimp_pointer *pointer);
+static bool ro_gui_options_interface_ok(wimp_w w);
+
+bool ro_gui_options_interface_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_selected_state(w, INTERFACE_STRIP_EXTNS_OPTION,
+ nsoption_bool(strip_extensions));
+ ro_gui_set_icon_selected_state(w, INTERFACE_CONFIRM_OVWR_OPTION,
+ nsoption_bool(confirm_overwrite));
+ ro_gui_set_icon_selected_state(w, INTERFACE_URL_COMPLETE_OPTION,
+ nsoption_bool(url_suggestion));
+ ro_gui_set_icon_selected_state(w, INTERFACE_HISTORY_TOOLTIP_OPTION,
+ nsoption_bool(history_tooltip));
+ ro_gui_set_icon_selected_state(w, INTERFACE_THUMBNAIL_ICONISE_OPTION,
+ nsoption_bool(thumbnail_iconise));
+ ro_gui_set_icon_selected_state(w, INTERFACE_USE_EXTERNAL_HOTLIST,
+ nsoption_bool(external_hotlists));
+ ro_gui_set_icon_string(w, INTERFACE_EXTERNAL_HOTLIST_APP,
+ (nsoption_charp(external_hotlist_app)) ?
+ nsoption_charp(external_hotlist_app) : "", false);
+
+ ro_gui_set_icon_shaded_state(w, INTERFACE_EXTERNAL_HOTLIST_APP,
+ !nsoption_bool(external_hotlists));
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_mouse_click(w,
+ ro_gui_options_interface_click);
+ ro_gui_wimp_event_register_button(w, INTERFACE_DEFAULT_BUTTON,
+ ro_gui_options_interface_default);
+ ro_gui_wimp_event_register_cancel(w, INTERFACE_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, INTERFACE_OK_BUTTON,
+ ro_gui_options_interface_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpInterfaceConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+
+bool ro_gui_options_interface_click(wimp_pointer *pointer)
+{
+ bool shaded;
+
+ switch (pointer->i) {
+ case INTERFACE_USE_EXTERNAL_HOTLIST:
+ shaded = !ro_gui_get_icon_selected_state(pointer->w,
+ INTERFACE_USE_EXTERNAL_HOTLIST);
+ ro_gui_set_icon_shaded_state(pointer->w,
+ INTERFACE_EXTERNAL_HOTLIST_APP, shaded);
+ return false;
+ break;
+ }
+ return false;
+}
+
+
+
+void ro_gui_options_interface_default(wimp_pointer *pointer)
+{
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_STRIP_EXTNS_OPTION, true);
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_CONFIRM_OVWR_OPTION, true);
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_URL_COMPLETE_OPTION, true);
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_HISTORY_TOOLTIP_OPTION, true);
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_THUMBNAIL_ICONISE_OPTION, true);
+ ro_gui_set_icon_selected_state(pointer->w,
+ INTERFACE_USE_EXTERNAL_HOTLIST, false);
+ ro_gui_set_icon_string(pointer->w, INTERFACE_EXTERNAL_HOTLIST_APP,
+ "", false);
+}
+
+bool ro_gui_options_interface_ok(wimp_w w)
+{
+ nsoption_set_bool(strip_extensions,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_STRIP_EXTNS_OPTION));
+ nsoption_set_bool(confirm_overwrite,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_CONFIRM_OVWR_OPTION));
+ nsoption_set_bool(url_suggestion,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_URL_COMPLETE_OPTION));
+ nsoption_set_bool(history_tooltip,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_HISTORY_TOOLTIP_OPTION));
+ nsoption_set_bool(thumbnail_iconise,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_THUMBNAIL_ICONISE_OPTION));
+ nsoption_set_bool(external_hotlists,
+ ro_gui_get_icon_selected_state(w,
+ INTERFACE_USE_EXTERNAL_HOTLIST));
+ nsoption_set_charp(external_hotlist_app,
+ strdup(ro_gui_get_icon_string(w,
+ INTERFACE_EXTERNAL_HOTLIST_APP)));
+
+ ro_gui_save_options();
+ return true;
+}
diff --git a/frontends/riscos/configure/con_language.c b/frontends/riscos/configure/con_language.c
new file mode 100644
index 000000000..2030c65c0
--- /dev/null
+++ b/frontends/riscos/configure/con_language.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/menus.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+
+#define LANGUAGE_INTERFACE_FIELD 3
+#define LANGUAGE_INTERFACE_GRIGHT 4
+#define LANGUAGE_WEB_PAGES_FIELD 6
+#define LANGUAGE_WEB_PAGES_GRIGHT 7
+#define LANGUAGE_DEFAULT_BUTTON 8
+#define LANGUAGE_CANCEL_BUTTON 9
+#define LANGUAGE_OK_BUTTON 10
+
+static void ro_gui_options_language_default(wimp_pointer *pointer);
+static bool ro_gui_options_language_ok(wimp_w w);
+static const char *ro_gui_options_language_name(const char *code);
+
+bool ro_gui_options_language_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_string(w, LANGUAGE_INTERFACE_FIELD,
+ ro_gui_options_language_name(nsoption_charp(language) ?
+ nsoption_charp(language) : "en"), true);
+ ro_gui_set_icon_string(w, LANGUAGE_WEB_PAGES_FIELD,
+ ro_gui_options_language_name(nsoption_charp(accept_language) ?
+ nsoption_charp(accept_language) : "en"), true);
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_menu_gright(w, LANGUAGE_INTERFACE_FIELD,
+ LANGUAGE_INTERFACE_GRIGHT, languages_menu);
+ ro_gui_wimp_event_register_menu_gright(w, LANGUAGE_WEB_PAGES_FIELD,
+ LANGUAGE_WEB_PAGES_GRIGHT, languages_menu);
+ ro_gui_wimp_event_register_button(w, LANGUAGE_DEFAULT_BUTTON,
+ ro_gui_options_language_default);
+ ro_gui_wimp_event_register_cancel(w, LANGUAGE_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, LANGUAGE_OK_BUTTON,
+ ro_gui_options_language_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpLanguageConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+void ro_gui_options_language_default(wimp_pointer *pointer)
+{
+ const char *code;
+
+ code = ro_gui_default_language();
+ ro_gui_set_icon_string(pointer->w, LANGUAGE_INTERFACE_FIELD,
+ ro_gui_options_language_name(code ?
+ code : "en"), true);
+ ro_gui_set_icon_string(pointer->w, LANGUAGE_WEB_PAGES_FIELD,
+ ro_gui_options_language_name(code ?
+ code : "en"), true);
+}
+
+bool ro_gui_options_language_ok(wimp_w w)
+{
+ const char *code;
+ char *temp;
+
+ code = ro_gui_menu_find_menu_entry_key(languages_menu,
+ ro_gui_get_icon_string(w, LANGUAGE_INTERFACE_FIELD));
+ if (code) {
+ code += 5; /* skip 'lang_' */
+ if ((!nsoption_charp(language)) ||
+ (strcmp(nsoption_charp(language), code))) {
+ temp = strdup(code);
+ if (temp) {
+ nsoption_set_charp(language, temp);
+ } else {
+ LOG("No memory to duplicate language code");
+ ro_warn_user("NoMemory", 0);
+ }
+ }
+ }
+ code = ro_gui_menu_find_menu_entry_key(languages_menu,
+ ro_gui_get_icon_string(w, LANGUAGE_WEB_PAGES_FIELD));
+ if (code) {
+ code += 5; /* skip 'lang_' */
+ if ((!nsoption_charp(accept_language)) ||
+ (strcmp(nsoption_charp(accept_language), code))) {
+ temp = strdup(code);
+ if (temp) {
+ nsoption_set_charp(accept_language,temp);
+ } else {
+ LOG("No memory to duplicate language code");
+ ro_warn_user("NoMemory", 0);
+ }
+ }
+ }
+ ro_gui_save_options();
+ return true;
+}
+
+
+/**
+ * Convert a 2-letter ISO language code to the language name.
+ *
+ * \param code 2-letter ISO language code
+ * \return language name, or code if unknown
+ */
+const char *ro_gui_options_language_name(const char *code)
+{
+ char key[] = "lang_xx";
+ key[5] = code[0];
+ key[6] = code[1];
+
+ return messages_get(key);
+}
diff --git a/frontends/riscos/configure/con_secure.c b/frontends/riscos/configure/con_secure.c
new file mode 100644
index 000000000..9c8a846c3
--- /dev/null
+++ b/frontends/riscos/configure/con_secure.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/configure.h"
+#include "riscos/configure/configure.h"
+#include "riscos/dialog.h"
+
+#define SECURITY_REFERRER 2
+#define SECURITY_DURATION_FIELD 6
+#define SECURITY_DURATION_INC 7
+#define SECURITY_DURATION_DEC 8
+#define SECURITY_DEFAULT_BUTTON 10
+#define SECURITY_CANCEL_BUTTON 11
+#define SECURITY_OK_BUTTON 12
+
+static void ro_gui_options_security_default(wimp_pointer *pointer);
+static bool ro_gui_options_security_ok(wimp_w w);
+
+bool ro_gui_options_security_initialise(wimp_w w)
+{
+ /* set the current values */
+ ro_gui_set_icon_selected_state(w, SECURITY_REFERRER,
+ nsoption_bool(send_referer));
+ ro_gui_set_icon_integer(w, SECURITY_DURATION_FIELD,
+ nsoption_int(expire_url));
+
+ /* initialise all functions for a newly created window */
+ ro_gui_wimp_event_register_checkbox(w, SECURITY_REFERRER);
+ ro_gui_wimp_event_register_numeric_field(w, SECURITY_DURATION_FIELD,
+ SECURITY_DURATION_DEC, SECURITY_DURATION_INC,
+ 0, 365, 1, 0);
+ ro_gui_wimp_event_register_button(w, SECURITY_DEFAULT_BUTTON,
+ ro_gui_options_security_default);
+ ro_gui_wimp_event_register_cancel(w, SECURITY_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, SECURITY_OK_BUTTON,
+ ro_gui_options_security_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpSecurityConfig");
+ ro_gui_wimp_event_memorise(w);
+ return true;
+
+}
+
+void ro_gui_options_security_default(wimp_pointer *pointer)
+{
+ /* set the default values */
+ ro_gui_set_icon_integer(pointer->w, SECURITY_DURATION_FIELD, 28);
+ ro_gui_set_icon_selected_state(pointer->w, SECURITY_REFERRER, true);
+}
+
+bool ro_gui_options_security_ok(wimp_w w)
+{
+ nsoption_set_bool(send_referer,
+ ro_gui_get_icon_selected_state(w, SECURITY_REFERRER));
+
+ nsoption_set_int(expire_url,
+ ro_gui_get_icon_decimal(w,SECURITY_DURATION_FIELD, 0));
+
+ ro_gui_save_options();
+ return true;
+}
diff --git a/frontends/riscos/configure/con_theme.c b/frontends/riscos/configure/con_theme.c
new file mode 100644
index 000000000..fb0d3dfb0
--- /dev/null
+++ b/frontends/riscos/configure/con_theme.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpspriteop.h>
+
+#include "utils/config.h"
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+
+#include "riscos/gui.h"
+#include "riscos/configure/configure.h"
+#include "riscos/configure.h"
+#include "riscos/dialog.h"
+#include "riscos/menus.h"
+#include "riscos/theme.h"
+#include "riscos/toolbar.h"
+#include "riscos/url_complete.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/wimputils.h"
+
+
+#define THEME_PANE_AREA 0
+#define THEME_DEFAULT_BUTTON 2
+#define THEME_CANCEL_BUTTON 3
+#define THEME_OK_BUTTON 4
+
+struct toolbar_display {
+ struct toolbar *toolbar;
+ struct theme_descriptor *descriptor;
+ int icon_number;
+ struct toolbar_display *next;
+};
+
+static wimp_window theme_pane_definition = {
+ {0, 0, 16, 16},
+ 0,
+ 0,
+ wimp_TOP,
+ wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_VSCROLL | wimp_WINDOW_AUTO_REDRAW,
+ wimp_COLOUR_BLACK,
+ wimp_COLOUR_LIGHT_GREY,
+ wimp_COLOUR_LIGHT_GREY,
+ wimp_COLOUR_VERY_LIGHT_GREY,
+ wimp_COLOUR_DARK_GREY,
+ wimp_COLOUR_MID_LIGHT_GREY,
+ wimp_COLOUR_CREAM,
+ 0,
+ {0, -16384, 16384, 0},
+ wimp_ICON_TEXT | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED,
+ wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT,
+ wimpspriteop_AREA,
+ 1,
+ 1,
+ {""},
+ 0,
+ {}
+};
+
+
+static wimp_w theme_pane;
+static struct theme_descriptor *theme_list = NULL;
+static struct toolbar_display *toolbars = NULL;
+static char theme_radio_validation[] = "Sradiooff,radioon";
+static char theme_null_validation[] = "";
+static char theme_line_validation[] = "R2";
+
+static bool ro_gui_options_theme_ok(wimp_w w);
+static bool ro_gui_options_theme_click(wimp_pointer *pointer);
+static void ro_gui_options_theme_load(void);
+static void ro_gui_options_theme_free(void);
+
+bool ro_gui_options_theme_initialise(wimp_w w)
+{
+ wimp_window_state state;
+ wimp_icon_state icon_state;
+ os_error *error;
+ struct theme_descriptor *theme_choice;
+ struct toolbar_display *toolbar;
+
+ /* only allow one instance for now*/
+ if (theme_pane)
+ return false;
+ error = xwimp_create_window(&theme_pane_definition, &theme_pane);
+ if (error) {
+ LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+ state.w = w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+ icon_state.w = w;
+ icon_state.i = THEME_PANE_AREA;
+ error = xwimp_get_icon_state(&icon_state);
+ if (error) {
+ LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+ state.w = theme_pane;
+ state.visible.x1 = state.visible.x0 + icon_state.icon.extent.x1 - 16 -
+ ro_get_vscroll_width(theme_pane);
+ state.visible.x0 += icon_state.icon.extent.x0 + 16;
+ state.visible.y0 = state.visible.y1 + icon_state.icon.extent.y0 + 16;
+ state.visible.y1 += icon_state.icon.extent.y1 - 28;
+ LOG("Y0 = %i, y1 = %i", icon_state.icon.extent.y0, icon_state.icon.extent.y1);
+ error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), w,
+ wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
+ << wimp_CHILD_XORIGIN_SHIFT |
+ wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
+ << wimp_CHILD_YORIGIN_SHIFT |
+ wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
+ << wimp_CHILD_LS_EDGE_SHIFT |
+ wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
+ << wimp_CHILD_BS_EDGE_SHIFT |
+ wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
+ << wimp_CHILD_RS_EDGE_SHIFT |
+ wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
+ << wimp_CHILD_TS_EDGE_SHIFT);
+ if (error) {
+ LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+
+ /* load themes */
+ ro_gui_options_theme_load();
+
+ /* set the current selection */
+ theme_choice = ro_gui_theme_find(nsoption_charp(theme));
+ if (!theme_choice)
+ theme_choice = ro_gui_theme_find("Aletheia");
+ for (toolbar = toolbars; toolbar; toolbar = toolbar->next)
+ ro_gui_set_icon_selected_state(theme_pane, toolbar->icon_number,
+ (toolbar->descriptor == theme_choice));
+ ro_gui_wimp_event_memorise(theme_pane);
+ ro_gui_wimp_event_set_help_prefix(theme_pane, "HelpThemePConfig");
+
+ ro_gui_wimp_event_register_mouse_click(w, ro_gui_options_theme_click);
+ ro_gui_wimp_event_register_cancel(w, THEME_CANCEL_BUTTON);
+ ro_gui_wimp_event_register_ok(w, THEME_OK_BUTTON,
+ ro_gui_options_theme_ok);
+ ro_gui_wimp_event_set_help_prefix(w, "HelpThemeConfig");
+ ro_gui_wimp_event_memorise(w);
+
+ return true;
+}
+
+void ro_gui_options_theme_finalise(wimp_w w)
+{
+ ro_gui_options_theme_free();
+ if (theme_pane) {
+ os_error *error;
+ ro_gui_wimp_event_finalise(theme_pane);
+ error = xwimp_delete_window(theme_pane);
+ if (error) {
+ LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ theme_pane = 0;
+ }
+ ro_gui_wimp_event_finalise(w);
+}
+
+bool ro_gui_options_theme_ok(wimp_w w)
+{
+ struct toolbar_display *toolbar;
+ struct theme_descriptor *theme_new = NULL;
+
+ /* find the current selection */
+ for (toolbar = toolbars; toolbar; toolbar = toolbar->next) {
+ if (ro_gui_get_icon_selected_state(theme_pane, toolbar->icon_number)) {
+ theme_new = toolbar->descriptor;
+ break;
+ }
+ }
+
+ /* set the options */
+ if (theme_new) {
+ nsoption_set_charp(theme, strdup(theme_new->leafname));
+ ro_gui_theme_apply(theme_new);
+ } else {
+ nsoption_set_charp(theme, NULL);
+ }
+ ro_gui_save_options();
+
+ /* store the pane status */
+ ro_gui_wimp_event_memorise(theme_pane);
+ return true;
+}
+
+bool ro_gui_options_theme_click(wimp_pointer *pointer)
+{
+ struct theme_descriptor *theme_default;
+ struct toolbar_display *toolbar;
+
+ switch (pointer->i) {
+ case THEME_DEFAULT_BUTTON:
+ theme_default = ro_gui_theme_find("Aletheia");
+ for (toolbar = toolbars; toolbar; toolbar = toolbar->next)
+ ro_gui_set_icon_selected_state(theme_pane,
+ toolbar->icon_number,
+ (toolbar->descriptor == theme_default));
+ break;
+ case THEME_CANCEL_BUTTON:
+ ro_gui_wimp_event_restore(theme_pane);
+ break;
+ case THEME_OK_BUTTON:
+ ro_gui_wimp_event_memorise(theme_pane);
+ break;
+ }
+ return false;
+}
+
+void ro_gui_options_theme_load(void)
+{
+ os_error *error;
+ os_box extent = { 0, 0, 0, 0 };
+ struct theme_descriptor *descriptor;
+ struct toolbar_display *link;
+ struct toolbar_display *toolbar_display;
+ struct toolbar *toolbar;
+ wimp_icon_create new_icon;
+ wimp_window_state state;
+ int parent_width, nested_y, min_extent, base_extent;
+ int *radio_icons, *radio_set;
+ int theme_count;
+
+ /* delete our old list and get/open a new one */
+ ro_gui_options_theme_free();
+ theme_list = ro_gui_theme_get_available();
+ ro_gui_theme_open(theme_list, true);
+
+ /* create toolbars for each theme */
+ theme_count = 0;
+ descriptor = theme_list;
+ while (descriptor != NULL) {
+ /* try to create a toolbar */
+ toolbar = ro_toolbar_create(descriptor, NULL,
+ THEME_STYLE_BROWSER_TOOLBAR,
+ TOOLBAR_FLAGS_DISPLAY, NULL, NULL, NULL);
+ if (toolbar != NULL) {
+ ro_toolbar_add_buttons(toolbar, brower_toolbar_buttons,
+ nsoption_charp(toolbar_browser));
+ ro_toolbar_add_url(toolbar);
+ ro_toolbar_add_throbber(toolbar);
+ ro_toolbar_rebuild(toolbar);
+ toolbar_display = calloc(sizeof(struct toolbar_display), 1);
+ if (!toolbar_display) {
+ LOG("No memory for calloc()");
+ ro_warn_user("NoMemory", 0);
+ return;
+ }
+ toolbar_display->toolbar = toolbar;
+ toolbar_display->descriptor = descriptor;
+ if (!toolbars) {
+ toolbars = toolbar_display;
+ } else {
+ link = toolbars;
+ while (link->next) link = link->next;
+ link->next = toolbar_display;
+ }
+ theme_count++;
+ }
+ descriptor = descriptor->next;
+ }
+
+ /* nest the toolbars */
+ state.w = theme_pane;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ parent_width = state.visible.x1 - state.visible.x0;
+ min_extent = state.visible.y0 - state.visible.y1;
+ nested_y = 0;
+ base_extent = state.visible.y1 - state.yscroll;
+ extent.x1 = parent_width;
+ link = toolbars;
+ new_icon.w = theme_pane;
+ new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
+ wimp_ICON_VCENTRED |
+ (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
+ (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT);
+ while (link) {
+ /* update the toolbar */
+ int item_height = 44 + 44 + 16;
+ if (link->next) item_height += 16;
+ ro_toolbar_process(link->toolbar, parent_width, false);
+ extent.y0 = nested_y -
+ ro_toolbar_height(link->toolbar) -
+ item_height;
+ if (link->next) extent.y0 -= 16;
+ if (extent.y0 > min_extent) extent.y0 = min_extent;
+ xwimp_set_extent(theme_pane, &extent);
+
+ /* create the descriptor icons and separator line */
+ new_icon.icon.extent.x0 = 8;
+ new_icon.icon.extent.x1 = parent_width - 8;
+ new_icon.icon.flags &= ~wimp_ICON_BORDER;
+ new_icon.icon.flags |= wimp_ICON_SPRITE;
+ new_icon.icon.extent.y1 = nested_y -
+ ro_toolbar_height(link->toolbar) - 8;
+ new_icon.icon.extent.y0 = nested_y -
+ ro_toolbar_height(link->toolbar) - 52;
+ new_icon.icon.data.indirected_text_and_sprite.text =
+ (char *)&link->descriptor->name;
+ new_icon.icon.data.indirected_text_and_sprite.size =
+ strlen(link->descriptor->name) + 1;
+ new_icon.icon.data.indirected_text_and_sprite.validation =
+ theme_radio_validation;
+ new_icon.icon.flags |= (wimp_BUTTON_RADIO <<
+ wimp_ICON_BUTTON_TYPE_SHIFT);
+ xwimp_create_icon(&new_icon, &link->icon_number);
+ new_icon.icon.flags &= ~wimp_ICON_SPRITE;
+ new_icon.icon.extent.x0 = 52;
+ new_icon.icon.extent.y1 -= 44;
+ new_icon.icon.extent.y0 -= 44;
+ new_icon.icon.data.indirected_text.text =
+ (char *)&link->descriptor->author;
+ new_icon.icon.data.indirected_text.size =
+ strlen(link->descriptor->author) + 1;
+ new_icon.icon.data.indirected_text.validation =
+ theme_null_validation;
+ new_icon.icon.flags &= ~(wimp_BUTTON_RADIO <<
+ wimp_ICON_BUTTON_TYPE_SHIFT);
+ xwimp_create_icon(&new_icon, 0);
+ if (link->next) {
+ new_icon.icon.flags |= wimp_ICON_BORDER;
+ new_icon.icon.extent.x0 = -8;
+ new_icon.icon.extent.x1 = parent_width + 8;
+ new_icon.icon.extent.y1 -= 52;
+ new_icon.icon.extent.y0 = new_icon.icon.extent.y1 - 8;
+ new_icon.icon.data.indirected_text.text =
+ theme_null_validation;
+ new_icon.icon.data.indirected_text.validation =
+ theme_line_validation;
+ new_icon.icon.data.indirected_text.size = 1;
+ xwimp_create_icon(&new_icon, 0);
+ }
+
+ /* nest the toolbar window */
+ state.w = ro_toolbar_get_window(link->toolbar);
+ state.yscroll = 0;
+ state.visible.y1 = nested_y + base_extent;
+ state.visible.y0 = state.visible.y1 -
+ ro_toolbar_height(link->toolbar) + 2;
+ xwimp_open_window_nested(PTR_WIMP_OPEN(&state), theme_pane,
+ wimp_CHILD_LINKS_PARENT_WORK_AREA
+ << wimp_CHILD_BS_EDGE_SHIFT |
+ wimp_CHILD_LINKS_PARENT_WORK_AREA
+ << wimp_CHILD_TS_EDGE_SHIFT);
+
+ /* continue processing */
+ nested_y -= ro_toolbar_height(link->toolbar) +
+ item_height;
+ link = link->next;
+ }
+
+ /* set the icons as radios */
+ radio_icons = (int *)calloc(theme_count + 1, sizeof(int));
+ radio_set = radio_icons;
+ for (link = toolbars; link; link = link->next)
+ *radio_set++ = link->icon_number;
+ *radio_set = -1;
+ ro_gui_wimp_event_register_radio(theme_pane, radio_icons);
+
+ /* update our display */
+ xwimp_force_redraw(theme_pane, 0, -16384, 16384, 16384);
+}
+
+void ro_gui_options_theme_free(void)
+{
+ struct toolbar_display *toolbar;
+ struct toolbar_display *next_toolbar;
+
+ /* free all our toolbars */
+ next_toolbar = toolbars;
+ while ((toolbar = next_toolbar) != NULL) {
+ next_toolbar = toolbar->next;
+ xwimp_delete_icon(theme_pane, toolbar->icon_number);
+ xwimp_delete_icon(theme_pane, toolbar->icon_number + 1);
+ if (next_toolbar)
+ xwimp_delete_icon(theme_pane,
+ toolbar->icon_number + 2);
+ ro_toolbar_destroy(toolbar->toolbar);
+ free(toolbar);
+ }
+ toolbars = NULL;
+
+ /* close all our themes */
+ if (theme_list)
+ ro_gui_theme_close(theme_list, true);
+ theme_list = NULL;
+}
diff --git a/frontends/riscos/configure/configure.h b/frontends/riscos/configure/configure.h
new file mode 100644
index 000000000..e5cdb392e
--- /dev/null
+++ b/frontends/riscos/configure/configure.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Automated RISC OS WIMP event handling (interface).
+ */
+
+
+#ifndef _NETSURF_RISCOS_OPTIONS_CONFIGURE_H_
+#define _NETSURF_RISCOS_OPTIONS_CONFIGURE_H_
+
+#include <stdbool.h>
+#include "oslib/wimp.h"
+
+bool ro_gui_options_cache_initialise(wimp_w w);
+bool ro_gui_options_connection_initialise(wimp_w w);
+bool ro_gui_options_content_initialise(wimp_w w);
+bool ro_gui_options_fonts_initialise(wimp_w w);
+bool ro_gui_options_home_initialise(wimp_w w);
+bool ro_gui_options_image_initialise(wimp_w w);
+void ro_gui_options_image_finalise(wimp_w w);
+bool ro_gui_options_interface_initialise(wimp_w w);
+bool ro_gui_options_language_initialise(wimp_w w);
+bool ro_gui_options_security_initialise(wimp_w w);
+bool ro_gui_options_theme_initialise(wimp_w w);
+void ro_gui_options_theme_finalise(wimp_w w);
+
+#endif
diff --git a/frontends/riscos/content-handlers/artworks.c b/frontends/riscos/content-handlers/artworks.c
new file mode 100644
index 000000000..b6f7a0d08
--- /dev/null
+++ b/frontends/riscos/content-handlers/artworks.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-artworks (RISC OS implementation).
+ *
+ * Uses the ArtworksRenderer module
+ */
+
+#include "utils/config.h"
+#ifdef WITH_ARTWORKS
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "swis.h"
+#include "oslib/os.h"
+#include "oslib/wimp.h"
+
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "content/content_protected.h"
+#include "desktop/plotters.h"
+
+#include "riscos/content-handlers/artworks.h"
+#include "riscos/gui.h"
+#include "riscos/wimputils.h"
+
+#define AWRender_FileInitAddress 0x46080
+#define AWRender_RenderAddress 0x46081
+#define AWRender_DocBounds 0x46082
+#define AWRender_SendDefs 0x46083
+#define AWRender_ClaimVectors 0x46084
+#define AWRender_ReleaseVectors 0x46085
+#define AWRender_FindFirstFont 0x46086
+#define AWRender_FindNextFont 0x46087
+
+
+#define INITIAL_BLOCK_SIZE 0x1000
+
+typedef struct artworks_content {
+ struct content base;
+
+ int x0, y0, x1, y1;
+
+ void *render_routine;
+ void *render_workspace;
+
+ /* dynamically-resizable block required by
+ ArtWorksRenderer rendering routine */
+
+ void *block;
+ size_t size;
+} artworks_content;
+
+struct awinfo_block {
+ int ditherx;
+ int dithery;
+ int clip_x0;
+ int clip_y0;
+ int clip_x1;
+ int clip_y1;
+ int print_lowx;
+ int print_lowy;
+ int print_handle;
+ int print_x1;
+ int print_y1;
+ int bgcolour;
+};
+
+
+/* Assembler routines for interfacing with the ArtworksRenderer module */
+
+extern os_error *awrender_init(const char **doc,
+ unsigned long *doc_size,
+ void *routine,
+ void *workspace);
+
+extern os_error *awrender_render(const char *doc,
+ const struct awinfo_block *info,
+ const os_trfm *trans,
+ const int *vdu_vars,
+ void **rsz_block,
+ size_t *rsz_size,
+ int wysiwyg_setting,
+ int output_dest,
+ size_t doc_size,
+ void *routine,
+ void *workspace);
+
+static nserror artworks_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c);
+static bool artworks_convert(struct content *c);
+static void artworks_destroy(struct content *c);
+static bool artworks_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx);
+static nserror artworks_clone(const struct content *old, struct content **newc);
+static content_type artworks_content_type(void);
+
+static const content_handler artworks_content_handler = {
+ .create = artworks_create,
+ .data_complete = artworks_convert,
+ .destroy = artworks_destroy,
+ .redraw = artworks_redraw,
+ .clone = artworks_clone,
+ .type = artworks_content_type,
+ .no_share = false,
+};
+
+static const char *artworks_types[] = {
+ "image/x-artworks"
+};
+
+CONTENT_FACTORY_REGISTER_TYPES(artworks, artworks_types,
+ artworks_content_handler)
+
+nserror artworks_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c)
+{
+ artworks_content *aw;
+ nserror error;
+
+ aw = calloc(1, sizeof(artworks_content));
+ if (aw == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__init(&aw->base, handler, imime_type, params,
+ llcache, fallback_charset, quirks);
+ if (error != NSERROR_OK) {
+ free(aw);
+ return error;
+ }
+
+ *c = (struct content *) aw;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Convert a CONTENT_ARTWORKS for display.
+ *
+ * No conversion is necessary. We merely read the ArtWorks
+ * bounding box bottom-left.
+ */
+
+bool artworks_convert(struct content *c)
+{
+ artworks_content *aw = (artworks_content *) c;
+ union content_msg_data msg_data;
+ const char *source_data;
+ unsigned long source_size;
+ void *init_workspace;
+ void *init_routine;
+ os_error *error;
+ int used = -1; /* slightly better with older OSLib versions */
+ char *title;
+
+ /* check whether AWViewer has been seen and we can therefore
+ locate the ArtWorks rendering modules */
+ xos_read_var_val_size("Alias$LoadArtWorksModules", 0, os_VARTYPE_STRING,
+ &used, NULL, NULL);
+ if (used >= 0) {
+ LOG("Alias$LoadArtWorksModules not defined");
+ msg_data.error = messages_get("AWNotSeen");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ /* load the modules, or do nothing if they're already loaded */
+ error = xos_cli("LoadArtWorksModules");
+ if (error) {
+ LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ /* lookup the addresses of the init and render routines */
+ error = (os_error*)_swix(AWRender_FileInitAddress, _OUT(0) | _OUT(1),
+ &init_routine, &init_workspace);
+ if (error) {
+ LOG("AWRender_FileInitAddress: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ error = (os_error*)_swix(AWRender_RenderAddress, _OUT(0) | _OUT(1),
+ &aw->render_routine,
+ &aw->render_workspace);
+ if (error) {
+ LOG("AWRender_RenderAddress: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ source_data = content__get_source_data(c, &source_size);
+
+ /* initialise (convert file to new format if required) */
+ error = awrender_init(&source_data, &source_size,
+ init_routine, init_workspace);
+ if (error) {
+ LOG("awrender_init: 0x%x : %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ error = (os_error*)_swix(AWRender_DocBounds,
+ _IN(0) | _OUT(2) | _OUT(3) | _OUT(4) | _OUT(5),
+ source_data,
+ &aw->x0,
+ &aw->y0,
+ &aw->x1,
+ &aw->y1);
+
+ if (error) {
+ LOG("AWRender_DocBounds: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ LOG("bounding box: %d,%d,%d,%d", aw->x0, aw->y0, aw->x1, aw->y1);
+
+ /* create the resizable workspace required by the
+ ArtWorksRenderer rendering routine */
+
+ aw->size = INITIAL_BLOCK_SIZE;
+ aw->block = malloc(INITIAL_BLOCK_SIZE);
+ if (!aw->block) {
+ LOG("failed to create block for ArtworksRenderer");
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ c->width = (aw->x1 - aw->x0) / 512;
+ c->height = (aw->y1 - aw->y0) / 512;
+
+ title = messages_get_buff("ArtWorksTitle",
+ nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
+ c->width, c->height);
+ if (title != NULL) {
+ content__set_title(c, title);
+ free(title);
+ }
+ content_set_ready(c);
+ content_set_done(c);
+ /* Done: update status bar */
+ content_set_status(c, "");
+ return true;
+}
+
+
+/**
+ * Destroy a CONTENT_ARTWORKS and free all resources it owns.
+ */
+
+void artworks_destroy(struct content *c)
+{
+ artworks_content *aw = (artworks_content *) c;
+
+ free(aw->block);
+}
+
+
+/**
+ * Redraw a CONTENT_ARTWORKS.
+ */
+
+bool artworks_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx)
+{
+ static const ns_os_vdu_var_list vars = {
+ os_MODEVAR_XEIG_FACTOR,
+ {
+ os_MODEVAR_YEIG_FACTOR,
+ os_MODEVAR_LOG2_BPP,
+ os_VDUVAR_END_LIST
+ }
+ };
+ artworks_content *aw = (artworks_content *) c;
+ struct awinfo_block info;
+ const char *source_data;
+ unsigned long source_size;
+ os_error *error;
+ os_trfm matrix;
+ int vals[24];
+
+ int clip_x0 = clip->x0;
+ int clip_y0 = clip->y0;
+ int clip_x1 = clip->x1;
+ int clip_y1 = clip->y1;
+
+ if (ctx->plot->flush && !ctx->plot->flush())
+ return false;
+
+ /* pick up render addresses again in case they've changed
+ (eg. newer AWRender module loaded since we first loaded this file) */
+ (void)_swix(AWRender_RenderAddress, _OUT(0) | _OUT(1),
+ &aw->render_routine,
+ &aw->render_workspace);
+
+ /* Scaled image. Transform units (65536*OS units) */
+ matrix.entries[0][0] = data->width * 65536 / c->width;
+ matrix.entries[0][1] = 0;
+ matrix.entries[1][0] = 0;
+ matrix.entries[1][1] = data->height * 65536 / c->height;
+ /* Draw units. (x,y) = bottom left */
+ matrix.entries[2][0] = ro_plot_origin_x * 256 + data->x * 512 -
+ aw->x0 * data->width / c->width;
+ matrix.entries[2][1] = ro_plot_origin_y * 256 -
+ (data->y + data->height) * 512 -
+ aw->y0 * data->height / c->height;
+
+ info.ditherx = ro_plot_origin_x;
+ info.dithery = ro_plot_origin_y;
+
+ clip_x0 -= data->x;
+ clip_y0 -= data->y;
+ clip_x1 -= data->x;
+ clip_y1 -= data->y;
+
+ if (data->scale == 1.0) {
+ info.clip_x0 = (clip_x0 * 512) + aw->x0 - 511;
+ info.clip_y0 = ((c->height - clip_y1) * 512) + aw->y0 - 511;
+ info.clip_x1 = (clip_x1 * 512) + aw->x0 + 511;
+ info.clip_y1 = ((c->height - clip_y0) * 512) + aw->y0 + 511;
+ }
+ else {
+ info.clip_x0 = (clip_x0 * 512 / data->scale) + aw->x0 - 511;
+ info.clip_y0 = ((c->height - (clip_y1 / data->scale)) * 512) +
+ aw->y0 - 511;
+ info.clip_x1 = (clip_x1 * 512 / data->scale) + aw->x0 + 511;
+ info.clip_y1 = ((c->height - (clip_y0 / data->scale)) * 512) +
+ aw->y0 + 511;
+ }
+
+ info.print_lowx = 0;
+ info.print_lowy = 0;
+ info.print_handle = 0;
+ info.bgcolour = 0x20000000 | data->background_colour;
+
+ error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), vals);
+ if (error) {
+ LOG("xos_read_vdu_variables: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+
+ error = xwimp_read_palette((os_palette*)&vals[3]);
+ if (error) {
+ LOG("xwimp_read_palette: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+
+ source_data = content__get_source_data(c, &source_size);
+
+ error = awrender_render(source_data,
+ &info,
+ &matrix,
+ vals,
+ &aw->block,
+ &aw->size,
+ 110, /* fully anti-aliased */
+ 0,
+ source_size,
+ aw->render_routine,
+ aw->render_workspace);
+
+ if (error) {
+ LOG("awrender_render: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+
+ return true;
+}
+
+nserror artworks_clone(const struct content *old, struct content **newc)
+{
+ artworks_content *aw;
+ nserror error;
+
+ aw = calloc(1, sizeof(artworks_content));
+ if (aw == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__clone(old, &aw->base);
+ if (error != NSERROR_OK) {
+ content_destroy(&aw->base);
+ return error;
+ }
+
+ /* Simply re-run convert */
+ if (old->status == CONTENT_STATUS_READY ||
+ old->status == CONTENT_STATUS_DONE) {
+ if (artworks_convert(&aw->base) == false) {
+ content_destroy(&aw->base);
+ return NSERROR_CLONE_FAILED;
+ }
+ }
+
+ *newc = (struct content *) aw;
+
+ return NSERROR_OK;
+}
+
+content_type artworks_content_type(void)
+{
+ return CONTENT_IMAGE;
+}
+
+#endif
diff --git a/frontends/riscos/content-handlers/artworks.h b/frontends/riscos/content-handlers/artworks.h
new file mode 100644
index 000000000..67832cc54
--- /dev/null
+++ b/frontends/riscos/content-handlers/artworks.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-artworks (RISC OS interface).
+ */
+
+#ifndef _NETSURF_RISCOS_ARTWORKS_H_
+#define _NETSURF_RISCOS_ARTWORKS_H_
+
+#include "utils/config.h"
+#include "utils/errors.h"
+
+#ifdef WITH_ARTWORKS
+
+nserror artworks_init(void);
+
+#else
+
+static inline nserror artworks_init(void)
+{
+ return NSERROR_OK;
+}
+
+#endif
+
+#endif
diff --git a/frontends/riscos/content-handlers/awrender.s b/frontends/riscos/content-handlers/awrender.s
new file mode 100644
index 000000000..5bcafe520
--- /dev/null
+++ b/frontends/riscos/content-handlers/awrender.s
@@ -0,0 +1,390 @@
+#if defined(__aof__)
+ AREA |ARM$$code|,CODE,READONLY
+
+ IMPORT messages_get
+ IMPORT realloc
+ IMPORT strcpy
+ IMPORT |__rt_stkovf_split_big|
+
+ EXPORT awrender_init
+ EXPORT awrender_render
+
+
+aw_rsz_block * 0
+aw_rsz_size * 4
+aw_fixed_block * 8
+aw_fixed_size * 12
+aw_sl * 16
+aw_fp * 20
+sizeof_aw * 24
+
+
+; os_error *awrender_init(byte **doc, size_t *doc_size, void *init_routine, void *init_workspace);
+
+awrender_init MOV ip,sp
+ STMFD sp!,{a1,a2,v1,v2,fp,ip,lr,pc}
+ SUB fp,ip,#4
+ SUB ip,sp,#512
+ CMP ip,sl
+ BLMI |__rt_stkovf_split_big|
+
+ LDR v2,=aw_temp
+ LDR a1,[a1]
+ MOV v1,a3
+ LDR a3,[a2]
+ MOV ip,a4
+ STR a1,[v2,#aw_rsz_block]
+ STR a3,[v2,#aw_rsz_size]
+ MOV a2,#-1
+ STR a2,[v2,#aw_fixed_block]
+ STR a3,[v2,#aw_fixed_size]
+ STR sl,[v2,#aw_sl]
+ STR fp,[v2,#aw_fp]
+ ADR a2,aw_callback
+ MOV lr,pc
+ MOV pc,v1
+ MOVVC a1,#0
+
+ ;return updated block ptr & size to caller
+
+ LDR a2,[fp,#-28]
+ LDR a3,[fp,#-24]
+ LDR ip,[v2,#aw_rsz_block]
+ LDR lr,[v2,#aw_rsz_size]
+ STR ip,[a2]
+ STR lr,[a3]
+
+ LDMEA fp,{v1,v2,fp,sp,pc}
+
+
+; os_error *awrender_render(const char *doc,
+; const struct awinfo_block *info,
+; const os_trfm *trans,
+; const int *vdu_vars,
+; char **rsz_block,
+; size_t *rsz_size,
+; int wysiwyg_setting,
+; int output_dest,
+; size_t doc_size,
+; void *routine,
+; void *workspace);
+
+awrender_render MOV ip,sp
+ STMFD sp!,{v1-v4,fp,ip,lr,pc}
+ SUB fp,ip,#4
+ SUB ip,sp,#512
+ CMP ip,sl
+ BLMI |__rt_stkovf_split_big|
+
+ LDR R12,[fp,#20]
+ LDR R14,=aw_temp
+ LDR R5,[fp,#4]
+ LDR R6,[fp,#12]
+ LDR R4,[R5] ;resizable block
+ LDR R7,[fp,#16]
+ STR R4,[R14,#aw_rsz_block]
+ STR R0,[R14,#aw_fixed_block] ;document ptr
+ STR R12,[R14,#aw_fixed_size] ;document size
+ LDR R12,[fp,#8]
+
+ STR R5,[sp,#-4]! ;ptr to receive block
+ STR R12,[sp,#-4]! ;ptr to receive size
+
+ LDR R12,[R12]
+ ADR R5,aw_callback
+ STR R12,[R14,#aw_rsz_size]
+
+ STR sl,[R14,#aw_sl]
+ STR fp,[R14,#aw_fp]
+
+ LDR R12,[fp,#28]
+ MOV lr,pc
+ LDR pc,[fp,#24]
+ MOVVC a1,#0
+
+ ;return updated block ptr & size to caller
+
+ LDR R7,=aw_temp
+ LDR R12,[sp],#4
+ LDR R4,[sp],#4
+ LDR R5,[R7,#aw_rsz_size]
+ LDR R6,[R7,#aw_rsz_block]
+ STR R5,[R12]
+ STR R6,[R4]
+
+ LDMEA fp,{v1-v4,fp,sp,pc}
+
+
+; Callback routine for block resizing
+; (passed to AWRender init and render routines)
+;
+; entry R11 = reason code
+; 0 = CallBackReason_Memory
+; 3 = CallBackReason_Interface
+; (0 => return capabilities)
+; exit R0 => base of resizable block
+; R1 = size of resizable block
+; R2 => base of fixed block (or -1 if no fixed block)
+; R3 = size of fixed block (or document in resizable block)
+; VC if resize successful, VS and R0 => error otherwise
+
+aw_callback TEQ R11,#3
+ TEQEQ R0,#0
+ MOVEQ R0,#1<<10 ;background colour supplied
+ TEQ R11,#0
+ LDREQ R11,=aw_temp
+ MOVNE PC,R14
+
+ CMP R0,#-1 ;read block size?
+ LDRNE R2,[R11,#aw_rsz_size]
+ MOVNE R1,R0 ;new block size
+ LDR R0,[R11,#aw_rsz_block]
+ BEQ aw_read
+
+ ; Note: because ArtworksRenderer seems to call
+ ; this routine for every scanline rendered
+ ; we never call realloc unless we have to in
+ ; order to expand the block. Also it calls
+ ; us with a size request of 0 which we must
+ ; safely ignore otherwise rendering will stop.
+
+ CMP R1,R2
+ BLS aw_read
+
+ STMFD R13!,{R1,R10-R12,R14}
+ LDR sl,[R11,#aw_sl]
+ LDR fp,[R11,#aw_fp]
+ BL realloc
+ LDMFD R13!,{R1,R10-R12,R14}
+
+ CMP R0,#0 ;did it work?
+ BEQ aw_nomem
+
+ STR R0,[R11]
+ STR R1,[R11,#aw_rsz_size]
+
+aw_read ; return details of fixed block
+
+ LDR R2,[R11,#aw_fixed_block]
+ LDR R3,[R11,#aw_fixed_size]
+ SUBS R11,R11,R11 ;clear V
+ MOV PC,R14
+
+aw_nomem STMFD R13!,{R10,R12,R14}
+ LDR sl,[R11,#aw_sl]
+ LDR fp,[R11,#aw_fp]
+ ADR R0,tok_nomem
+ BL messages_get
+ MOV a2,a1
+ LDR a1,=errblk + 4
+ BL strcpy
+ SUB R0,R0,#4 ;error number already 0
+ MOV R11,#0 ;restore reason code
+ CMP PC,#1<<31 ;set V
+ LDMFD R13!,{R10,R12,PC}
+
+tok_nomem = "NoMemory",0
+ ALIGN
+
+
+ AREA |ARM$$zidata|,DATA,NOINIT
+
+aw_temp % sizeof_aw
+errblk % 256
+
+ END
+
+#elif defined(__ELF__)
+
+ .text
+
+.set aw_rsz_block, 0
+.set aw_rsz_size, 4
+.set aw_fixed_block, 8
+.set aw_fixed_size, 12
+.set aw_sl, 16
+.set aw_fp, 20
+.set sizeof_aw, 24
+
+@ os_error *awrender_init(byte **doc, size_t *doc_size, void *init_routine, void *init_workspace);
+
+ .global awrender_init
+awrender_init: MOV ip,sp
+ STMFD sp!,{a1,a2,v1,v2,fp,ip,lr,pc}
+ SUB fp,ip,#4
+ SUB ip,sp,#512
+ CMP ip,sl
+ BLMI __rt_stkovf_split_big
+
+ LDR v2,=aw_temp
+ LDR a1,[a1]
+ MOV v1,a3
+ LDR a3,[a2]
+ MOV ip,a4
+ STR a1,[v2,#aw_rsz_block]
+ STR a3,[v2,#aw_rsz_size]
+ MOV a2,#-1
+ STR a2,[v2,#aw_fixed_block]
+ STR a3,[v2,#aw_fixed_size]
+ STR sl,[v2,#aw_sl]
+ STR fp,[v2,#aw_fp]
+ ADR a2,aw_callback
+ MOV lr,pc
+ MOV pc,v1
+ MOVVC a1,#0
+
+ @ return updated block ptr & size to caller
+
+ LDR a2,[fp,#-28]
+ LDR a3,[fp,#-24]
+ LDR ip,[v2,#aw_rsz_block]
+ LDR lr,[v2,#aw_rsz_size]
+ STR ip,[a2]
+ STR lr,[a3]
+
+ LDMEA fp,{v1,v2,fp,sp,pc}
+
+
+@ os_error *awrender_render(const char *doc,
+@ const struct awinfo_block *info,
+@ const os_trfm *trans,
+@ const int *vdu_vars,
+@ char **rsz_block,
+@ size_t *rsz_size,
+@ int wysiwyg_setting,
+@ int output_dest,
+@ size_t doc_size,
+@ void *routine,
+@ void *workspace);
+
+ .global awrender_render
+awrender_render: MOV ip,sp
+ STMFD sp!,{v1-v4,fp,ip,lr,pc}
+ SUB fp,ip,#4
+ SUB ip,sp,#512
+ CMP ip,sl
+ BLMI __rt_stkovf_split_big
+
+ LDR R12,[fp,#20]
+ LDR R14,=aw_temp
+ LDR R5,[fp,#4]
+ LDR R6,[fp,#12]
+ LDR R4,[R5] @ resizable block
+ LDR R7,[fp,#16]
+ STR R4,[R14,#aw_rsz_block]
+ STR R0,[R14,#aw_fixed_block] @ document ptr
+ STR R12,[R14,#aw_fixed_size] @ document size
+ LDR R12,[fp,#8]
+
+ STR R5,[sp,#-4]! @ ptr to receive block
+ STR R12,[sp,#-4]! @ ptr to receive size
+
+ LDR R12,[R12]
+ ADR R5,aw_callback
+ STR R12,[R14,#aw_rsz_size]
+
+ STR sl,[R14,#aw_sl]
+ STR fp,[R14,#aw_fp]
+
+ LDR R12,[fp,#28]
+ MOV lr,pc
+ LDR pc,[fp,#24]
+ MOVVC a1,#0
+
+ @ return updated block ptr & size to caller
+
+ LDR R7,=aw_temp
+ LDR R12,[sp],#4
+ LDR R4,[sp],#4
+ LDR R5,[R7,#aw_rsz_size]
+ LDR R6,[R7,#aw_rsz_block]
+ STR R5,[R12]
+ STR R6,[R4]
+
+ LDMEA fp,{v1-v4,fp,sp,pc}
+
+
+@ Callback routine for block resizing
+@ (passed to AWRender init and render routines)
+@
+@ entry R11 = reason code
+@ 0 = CallBackReason_Memory
+@ 3 = CallBackReason_Interface
+@ (0 => return capabilities)
+@ exit R0 => base of resizable block
+@ R1 = size of resizable block
+@ R2 => base of fixed block (or -1 if no fixed block)
+@ R3 = size of fixed block (or document in resizable block)
+@ VC if resize successful, VS and R0 => error otherwise
+
+aw_callback: TEQ R11,#3
+ TEQEQ R0,#0
+ MOVEQ R0,#1<<10 @ background colour supplied
+ TEQ R11,#0
+ LDREQ R11,=aw_temp
+ MOVNE PC,R14
+
+ CMP R0,#-1 @ read block size?
+ LDRNE R2,[R11,#aw_rsz_size]
+ MOVNE R1,R0 @ new block size
+ LDR R0,[R11,#aw_rsz_block]
+ BEQ aw_read
+
+ @ Note: because ArtworksRenderer seems to call
+ @ this routine for every scanline rendered
+ @ we never call realloc unless we have to in
+ @ order to expand the block. Also it calls
+ @ us with a size request of 0 which we must
+ @ safely ignore otherwise rendering will stop.
+
+ CMP R1,R2
+ BLS aw_read
+
+ STMFD R13!,{R1,R10-R12,R14}
+ LDR sl,[R11,#aw_sl]
+ LDR fp,[R11,#aw_fp]
+ BL realloc
+ LDMFD R13!,{R1,R10-R12,R14}
+
+ CMP R0,#0 @ did it work?
+ BEQ aw_nomem
+
+ STR R0,[R11]
+ STR R1,[R11,#aw_rsz_size]
+
+aw_read: @ return details of fixed block
+
+ LDR R2,[R11,#aw_fixed_block]
+ LDR R3,[R11,#aw_fixed_size]
+ SUBS R11,R11,R11 @ clear V
+ MOV PC,R14
+
+aw_nomem: STMFD R13!,{R10,R12,R14}
+ LDR sl,[R11,#aw_sl]
+ LDR fp,[R11,#aw_fp]
+ ADR R0,tok_nomem
+ BL messages_get
+ MOV a2,a1
+ LDR a1,=errblk + 4
+ BL strcpy
+ SUB R0,R0,#4 @ error number already 0
+ MOV R11,#0 @ restore reason code
+ CMP PC,#1<<31 @ set V
+ LDMFD R13!,{R10,R12,PC}
+
+tok_nomem: .asciz "NoMemory"
+ .align
+
+ .bss
+
+aw_temp: .space sizeof_aw
+ .type aw_temp, %object
+ .size aw_temp, . - aw_temp
+
+errblk: .space 256
+ .type errblk, %object
+ .size errblk, . - errblk
+
+ .end
+#endif
+
diff --git a/frontends/riscos/content-handlers/draw.c b/frontends/riscos/content-handlers/draw.c
new file mode 100644
index 000000000..f2bee16dc
--- /dev/null
+++ b/frontends/riscos/content-handlers/draw.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-drawfile (RISC OS implementation).
+ *
+ * The DrawFile module is used to plot the DrawFile.
+ */
+
+#include "utils/config.h"
+#ifdef WITH_DRAW
+
+#include <string.h>
+#include <stdlib.h>
+#include "oslib/drawfile.h"
+
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "content/content_protected.h"
+#include "desktop/plotters.h"
+
+#include "riscos/content-handlers/draw.h"
+#include "riscos/gui.h"
+
+typedef struct draw_content {
+ struct content base;
+
+ int x0, y0;
+} draw_content;
+
+static nserror draw_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c);
+static bool draw_convert(struct content *c);
+static void draw_destroy(struct content *c);
+static bool draw_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx);
+static nserror draw_clone(const struct content *old, struct content **newc);
+static content_type draw_content_type(void);
+
+static const content_handler draw_content_handler = {
+ .create = draw_create,
+ .data_complete = draw_convert,
+ .destroy = draw_destroy,
+ .redraw = draw_redraw,
+ .clone = draw_clone,
+ .type = draw_content_type,
+ .no_share = false,
+};
+
+static const char *draw_types[] = {
+ "application/drawfile",
+ "application/x-drawfile",
+ "image/drawfile",
+ "image/x-drawfile"
+};
+
+CONTENT_FACTORY_REGISTER_TYPES(draw, draw_types, draw_content_handler)
+
+nserror draw_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c)
+{
+ draw_content *draw;
+ nserror error;
+
+ draw = calloc(1, sizeof(draw_content));
+ if (draw == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__init(&draw->base, handler, imime_type, params,
+ llcache, fallback_charset, quirks);
+ if (error != NSERROR_OK) {
+ free(draw);
+ return error;
+ }
+
+ *c = (struct content *) draw;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Convert a CONTENT_DRAW for display.
+ *
+ * No conversion is necessary. We merely read the DrawFile dimensions and
+ * bounding box bottom-left.
+ */
+
+bool draw_convert(struct content *c)
+{
+ draw_content *draw = (draw_content *) c;
+ union content_msg_data msg_data;
+ const char *source_data;
+ unsigned long source_size;
+ const void *data;
+ os_box bbox;
+ os_error *error;
+ char *title;
+
+ source_data = content__get_source_data(c, &source_size);
+ data = source_data;
+
+ /* BBox contents in Draw units (256*OS unit) */
+ error = xdrawfile_bbox(0, (drawfile_diagram *) data,
+ (int) source_size, 0, &bbox);
+ if (error) {
+ LOG("xdrawfile_bbox: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ if (bbox.x1 > bbox.x0 && bbox.y1 > bbox.y0) {
+ /* c->width & c->height stored as (OS units/2)
+ => divide by 512 to convert from draw units */
+ c->width = ((bbox.x1 - bbox.x0) / 512);
+ c->height = ((bbox.y1 - bbox.y0) / 512);
+ }
+ else
+ /* invalid/undefined bounding box */
+ c->height = c->width = 0;
+
+ draw->x0 = bbox.x0;
+ draw->y0 = bbox.y0;
+
+ title = messages_get_buff("DrawTitle",
+ nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
+ c->width, c->height);
+ if (title != NULL) {
+ content__set_title(c, title);
+ free(title);
+ }
+
+ content_set_ready(c);
+ content_set_done(c);
+ /* Done: update status bar */
+ content_set_status(c, "");
+ return true;
+}
+
+
+/**
+ * Destroy a CONTENT_DRAW and free all resources it owns.
+ */
+
+void draw_destroy(struct content *c)
+{
+}
+
+
+/**
+ * Redraw a CONTENT_DRAW.
+ */
+
+bool draw_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx)
+{
+ draw_content *draw = (draw_content *) c;
+ os_trfm matrix;
+ const char *source_data;
+ unsigned long source_size;
+ const void *src_data;
+ os_error *error;
+
+ if (ctx->plot->flush && !ctx->plot->flush())
+ return false;
+
+ if (!c->width || !c->height)
+ return false;
+
+ source_data = content__get_source_data(c, &source_size);
+ src_data = source_data;
+
+ /* Scaled image. Transform units (65536*OS units) */
+ matrix.entries[0][0] = data->width * 65536 / c->width;
+ matrix.entries[0][1] = 0;
+ matrix.entries[1][0] = 0;
+ matrix.entries[1][1] = data->height * 65536 / c->height;
+ /* Draw units. (x,y) = bottom left */
+ matrix.entries[2][0] = ro_plot_origin_x * 256 + data->x * 512 -
+ draw->x0 * data->width / c->width;
+ matrix.entries[2][1] = ro_plot_origin_y * 256 -
+ (data->y + data->height) * 512 -
+ draw->y0 * data->height / c->height;
+
+ error = xdrawfile_render(0, (drawfile_diagram *) src_data,
+ (int) source_size, &matrix, 0, 0);
+ if (error) {
+ LOG("xdrawfile_render: 0x%x: %s", error->errnum, error->errmess);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Clone a CONTENT_DRAW
+ */
+
+nserror draw_clone(const struct content *old, struct content **newc)
+{
+ draw_content *draw;
+ nserror error;
+
+ draw = calloc(1, sizeof(draw_content));
+ if (draw == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__clone(old, &draw->base);
+ if (error != NSERROR_OK) {
+ content_destroy(&draw->base);
+ return error;
+ }
+
+ /* Simply rerun convert */
+ if (old->status == CONTENT_STATUS_READY ||
+ old->status == CONTENT_STATUS_DONE) {
+ if (draw_convert(&draw->base) == false) {
+ content_destroy(&draw->base);
+ return NSERROR_CLONE_FAILED;
+ }
+ }
+
+ *newc = (struct content *) draw;
+
+ return NSERROR_OK;
+}
+
+content_type draw_content_type(void)
+{
+ return CONTENT_IMAGE;
+}
+
+#endif
diff --git a/frontends/riscos/content-handlers/draw.h b/frontends/riscos/content-handlers/draw.h
new file mode 100644
index 000000000..9f5baf6dc
--- /dev/null
+++ b/frontends/riscos/content-handlers/draw.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-drawfile (RISC OS interface).
+ */
+
+#ifndef _NETSURF_RISCOS_DRAW_H_
+#define _NETSURF_RISCOS_DRAW_H_
+
+#include "utils/config.h"
+#include "utils/errors.h"
+
+#ifdef WITH_DRAW
+
+nserror draw_init(void);
+
+#else
+
+static inline nserror draw_init(void)
+{
+ return NSERROR_OK;
+}
+
+#endif /* WITH_DRAW */
+
+#endif
diff --git a/frontends/riscos/content-handlers/sprite.c b/frontends/riscos/content-handlers/sprite.c
new file mode 100644
index 000000000..12fed4931
--- /dev/null
+++ b/frontends/riscos/content-handlers/sprite.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-riscos-sprite (RISC OS implementation).
+ *
+ * No conversion is necessary: we can render RISC OS sprites directly under
+ * RISC OS.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "oslib/osspriteop.h"
+
+#include "utils/config.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "content/content_protected.h"
+#include "desktop/plotters.h"
+
+#include "riscos/gui.h"
+#include "riscos/image.h"
+#include "riscos/content-handlers/sprite.h"
+
+#ifdef WITH_SPRITE
+
+typedef struct sprite_content {
+ struct content base;
+
+ void *data;
+} sprite_content;
+
+static nserror sprite_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c);
+static bool sprite_convert(struct content *c);
+static void sprite_destroy(struct content *c);
+static bool sprite_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx);
+static nserror sprite_clone(const struct content *old, struct content **newc);
+static content_type sprite_content_type(void);
+
+static const content_handler sprite_content_handler = {
+ .create = sprite_create,
+ .data_complete = sprite_convert,
+ .destroy = sprite_destroy,
+ .redraw = sprite_redraw,
+ .clone = sprite_clone,
+ .type = sprite_content_type,
+ .no_share = false,
+};
+
+static const char *sprite_types[] = {
+ "image/x-riscos-sprite"
+};
+
+CONTENT_FACTORY_REGISTER_TYPES(sprite, sprite_types, sprite_content_handler)
+
+nserror sprite_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
+ llcache_handle *llcache, const char *fallback_charset,
+ bool quirks, struct content **c)
+{
+ sprite_content *sprite;
+ nserror error;
+
+ sprite = calloc(1, sizeof(sprite_content));
+ if (sprite == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__init(&sprite->base, handler, imime_type, params,
+ llcache, fallback_charset, quirks);
+ if (error != NSERROR_OK) {
+ free(sprite);
+ return error;
+ }
+
+ *c = (struct content *) sprite;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Convert a CONTENT_SPRITE for display.
+ *
+ * No conversion is necessary. We merely read the sprite dimensions.
+ */
+
+bool sprite_convert(struct content *c)
+{
+ sprite_content *sprite = (sprite_content *) c;
+ os_error *error;
+ int w, h;
+ union content_msg_data msg_data;
+ const char *source_data;
+ unsigned long source_size;
+ const void *sprite_data;
+ char *title;
+
+ source_data = content__get_source_data(c, &source_size);
+
+ sprite_data = source_data - 4;
+ osspriteop_area *area = (osspriteop_area*) sprite_data;
+ sprite->data = area;
+
+ /* check for bad data */
+ if ((int)source_size + 4 != area->used) {
+ msg_data.error = messages_get("BadSprite");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ error = xosspriteop_read_sprite_info(osspriteop_PTR,
+ (osspriteop_area *)0x100,
+ (osspriteop_id) ((char *) area + area->first),
+ &w, &h, NULL, NULL);
+ if (error) {
+ LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess);
+ msg_data.error = error->errmess;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ return false;
+ }
+
+ c->width = w;
+ c->height = h;
+
+ /* set title text */
+ title = messages_get_buff("SpriteTitle",
+ nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
+ c->width, c->height);
+ if (title != NULL) {
+ content__set_title(c, title);
+ free(title);
+ }
+ content_set_ready(c);
+ content_set_done(c);
+ /* Done: update status bar */
+ content_set_status(c, "");
+ return true;
+}
+
+
+/**
+ * Destroy a CONTENT_SPRITE and free all resources it owns.
+ */
+
+void sprite_destroy(struct content *c)
+{
+ /* do not free c->data.sprite.data at it is simply a pointer to
+ * 4 bytes beforec->source_data. */
+}
+
+
+/**
+ * Redraw a CONTENT_SPRITE.
+ */
+
+bool sprite_redraw(struct content *c, struct content_redraw_data *data,
+ const struct rect *clip, const struct redraw_context *ctx)
+{
+ sprite_content *sprite = (sprite_content *) c;
+
+ if (ctx->plot->flush && !ctx->plot->flush())
+ return false;
+
+ return image_redraw(sprite->data,
+ ro_plot_origin_x + data->x * 2,
+ ro_plot_origin_y - data->y * 2,
+ data->width, data->height,
+ c->width,
+ c->height,
+ data->background_colour,
+ false, false, false,
+ IMAGE_PLOT_OS);
+}
+
+nserror sprite_clone(const struct content *old, struct content **newc)
+{
+ sprite_content *sprite;
+ nserror error;
+
+ sprite = calloc(1, sizeof(sprite_content));
+ if (sprite == NULL)
+ return NSERROR_NOMEM;
+
+ error = content__clone(old, &sprite->base);
+ if (error != NSERROR_OK) {
+ content_destroy(&sprite->base);
+ return error;
+ }
+
+ /* Simply rerun convert */
+ if (old->status == CONTENT_STATUS_READY ||
+ old->status == CONTENT_STATUS_DONE) {
+ if (sprite_convert(&sprite->base) == false) {
+ content_destroy(&sprite->base);
+ return NSERROR_CLONE_FAILED;
+ }
+ }
+
+ *newc = (struct content *) sprite;
+
+ return NSERROR_OK;
+}
+
+content_type sprite_content_type(void)
+{
+ return CONTENT_IMAGE;
+}
+
+#endif
+
+
+/**
+ * Returns the bit depth of a sprite
+ *
+ * \param s sprite
+ * \return depth in bpp
+ */
+
+byte sprite_bpp(const osspriteop_header *s)
+{
+ /* bit 31 indicates the presence of a full alpha channel
+ * rather than a binary mask */
+ int type = ((unsigned)s->mode >> osspriteop_TYPE_SHIFT) & 15;
+ byte bpp = 0;
+
+ switch (type) {
+ case osspriteop_TYPE_OLD:
+ {
+ bits psr;
+ int val;
+ if (!xos_read_mode_variable(s->mode,
+ os_MODEVAR_LOG2_BPP, &val, &psr) &&
+ !(psr & _C))
+ bpp = 1 << val;
+ }
+ break;
+ case osspriteop_TYPE1BPP: bpp = 1; break;
+ case osspriteop_TYPE2BPP: bpp = 2; break;
+ case osspriteop_TYPE4BPP: bpp = 4; break;
+ case osspriteop_TYPE8BPP: bpp = 8; break;
+ case osspriteop_TYPE16BPP: bpp = 16; break;
+ case osspriteop_TYPE32BPP: bpp = 32; break;
+ case osspriteop_TYPE_CMYK: bpp = 32; break;
+ }
+ return bpp;
+}
diff --git a/frontends/riscos/content-handlers/sprite.h b/frontends/riscos/content-handlers/sprite.h
new file mode 100644
index 000000000..ab6d312a5
--- /dev/null
+++ b/frontends/riscos/content-handlers/sprite.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/x-riscos-sprite (RISC OS interface).
+ */
+
+#ifndef _NETSURF_RISCOS_SPRITE_H_
+#define _NETSURF_RISCOS_SPRITE_H_
+
+#include "utils/config.h"
+#include "utils/errors.h"
+
+#ifdef WITH_SPRITE
+
+nserror sprite_init(void);
+
+#else
+
+static inline nserror sprite_init(void)
+{
+ return NSERROR_OK;
+}
+
+#endif
+
+byte sprite_bpp(const osspriteop_header *s);
+
+#endif
diff --git a/frontends/riscos/cookies.c b/frontends/riscos/cookies.c
new file mode 100644
index 000000000..93c9f39cf
--- /dev/null
+++ b/frontends/riscos/cookies.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Cookies (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "oslib/wimp.h"
+#include "oslib/wimpspriteop.h"
+
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+#include "utils/log.h"
+#include "content/urldb.h"
+#include "desktop/cookie_manager.h"
+#include "desktop/tree.h"
+#include "desktop/textinput.h"
+
+#include "riscos/cookies.h"
+#include "riscos/dialog.h"
+#include "riscos/menus.h"
+#include "riscos/toolbar.h"
+#include "riscos/treeview.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+
+static void ro_gui_cookies_toolbar_update_buttons(void);
+static void ro_gui_cookies_toolbar_save_buttons(char *config);
+static bool ro_gui_cookies_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_pointer *pointer);
+static void ro_gui_cookies_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+static bool ro_gui_cookies_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action);
+static void ro_gui_cookies_toolbar_click(button_bar_action action);
+
+struct ro_treeview_callbacks ro_cookies_treeview_callbacks = {
+ ro_gui_cookies_toolbar_click,
+ ro_gui_cookies_toolbar_update_buttons,
+ ro_gui_cookies_toolbar_save_buttons
+};
+
+/* The RISC OS cookie window, toolbar and treeview data. */
+
+static struct ro_cookies_window {
+ wimp_w window;
+ struct toolbar *toolbar;
+ ro_treeview *tv;
+ wimp_menu *menu;
+} cookies_window;
+
+/**
+ * Pre-Initialise the cookies tree. This is called for things that
+ * need to be done at the gui_init() stage, such as loading templates.
+ */
+
+void ro_gui_cookies_preinitialise(void)
+{
+ /* Create our window. */
+
+ cookies_window.window = ro_gui_dialog_create("tree");
+ ro_gui_set_window_title(cookies_window.window,
+ messages_get("Cookies"));
+}
+
+/**
+ * Initialise cookies tree, at the gui_init2() stage.
+ */
+
+void ro_gui_cookies_postinitialise(void)
+{
+ /* Create our toolbar. */
+
+ cookies_window.toolbar = ro_toolbar_create(NULL, cookies_window.window,
+ THEME_STYLE_COOKIES_TOOLBAR, TOOLBAR_FLAGS_NONE,
+ ro_treeview_get_toolbar_callbacks(), NULL,
+ "HelpCookiesToolbar");
+ if (cookies_window.toolbar != NULL) {
+ ro_toolbar_add_buttons(cookies_window.toolbar,
+ cookies_toolbar_buttons,
+ nsoption_charp(toolbar_cookies));
+ ro_toolbar_rebuild(cookies_window.toolbar);
+ }
+
+ /* Create the treeview with the window and toolbar. */
+
+ cookies_window.tv = ro_treeview_create(cookies_window.window,
+ cookies_window.toolbar, &ro_cookies_treeview_callbacks,
+ TREE_COOKIES);
+ if (cookies_window.tv == NULL) {
+ LOG("Failed to allocate treeview");
+ return;
+ }
+
+ ro_toolbar_update_client_data(cookies_window.toolbar,
+ cookies_window.tv);
+
+ /* Build the cookies window menu. */
+
+ static const struct ns_menu cookies_definition = {
+ "Cookies", {
+ { "Cookies", NO_ACTION, 0 },
+ { "Cookies.Expand", TREE_EXPAND_ALL, 0 },
+ { "Cookies.Expand.All", TREE_EXPAND_ALL, 0 },
+ { "Cookies.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
+ { "Cookies.Expand.Links", TREE_EXPAND_LINKS, 0 },
+ { "Cookies.Collapse", TREE_COLLAPSE_ALL, 0 },
+ { "Cookies.Collapse.All", TREE_COLLAPSE_ALL, 0 },
+ { "Cookies.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
+ { "Cookies.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
+ { "Cookies.Toolbars", NO_ACTION, 0 },
+ { "_Cookies.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "Cookies.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
+ { "Selection", TREE_SELECTION, 0 },
+ { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
+ { "SelectAll", TREE_SELECT_ALL, 0 },
+ { "Clear", TREE_CLEAR_SELECTION, 0 },
+ {NULL, 0, 0}
+ }
+ };
+ cookies_window.menu = ro_gui_menu_define_menu(&cookies_definition);
+
+ ro_gui_wimp_event_register_menu(cookies_window.window,
+ cookies_window.menu, false, false);
+ ro_gui_wimp_event_register_menu_prepare(cookies_window.window,
+ ro_gui_cookies_menu_prepare);
+ ro_gui_wimp_event_register_menu_selection(cookies_window.window,
+ ro_gui_cookies_menu_select);
+ ro_gui_wimp_event_register_menu_warning(cookies_window.window,
+ ro_gui_cookies_menu_warning);
+}
+
+/**
+ * Destroy the cookies window.
+ */
+
+void ro_gui_cookies_destroy(void)
+{
+ if (cookies_window.tv == NULL)
+ return;
+
+ ro_treeview_destroy(cookies_window.tv);
+}
+
+/**
+ * Open the cookies window.
+ *
+ */
+
+void ro_gui_cookies_open(void)
+{
+ ro_gui_cookies_toolbar_update_buttons();
+
+ if (!ro_gui_dialog_open_top(cookies_window.window,
+ cookies_window.toolbar, 600, 800)) {
+ ro_treeview_set_origin(cookies_window.tv, 0,
+ -(ro_toolbar_height(cookies_window.toolbar)));
+ }
+}
+
+
+/**
+ * Handle toolbar button clicks.
+ *
+ * \param action The action to handle
+ */
+
+void ro_gui_cookies_toolbar_click(button_bar_action action)
+{
+ switch (action) {
+ case TOOLBAR_BUTTON_DELETE:
+ cookie_manager_keypress(NS_KEY_DELETE_LEFT);
+ break;
+
+ case TOOLBAR_BUTTON_EXPAND:
+ cookie_manager_expand(false);
+ break;
+
+ case TOOLBAR_BUTTON_COLLAPSE:
+ cookie_manager_contract(false);
+ break;
+
+ case TOOLBAR_BUTTON_OPEN:
+ cookie_manager_expand(true);
+ break;
+
+ case TOOLBAR_BUTTON_CLOSE:
+ cookie_manager_contract(true);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Update the button state in the cookies toolbar.
+ */
+
+void ro_gui_cookies_toolbar_update_buttons(void)
+{
+ ro_toolbar_set_button_shaded_state(cookies_window.toolbar,
+ TOOLBAR_BUTTON_DELETE,
+ !cookie_manager_has_selection());
+}
+
+
+/**
+ * Save a new button arrangement in the cookies toolbar.
+ *
+ * \param *config The new button configuration string.
+ */
+
+void ro_gui_cookies_toolbar_save_buttons(char *config)
+{
+ nsoption_set_charp(toolbar_cookies, config);
+ ro_gui_save_options();
+}
+
+
+/**
+ * Prepare the cookies menu for opening
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu about to be opened.
+ * \param *pointer Pointer to the relevant wimp event block, or
+ * NULL for an Adjust click.
+ * \return true if the event was handled; else false.
+ */
+
+bool ro_gui_cookies_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_pointer *pointer)
+{
+ bool selection;
+
+ if (menu != cookies_window.menu)
+ return false;
+
+ selection = cookie_manager_has_selection();
+
+ ro_gui_menu_set_entry_shaded(cookies_window.menu,
+ TREE_SELECTION, !selection);
+ ro_gui_menu_set_entry_shaded(cookies_window.menu,
+ TREE_CLEAR_SELECTION, !selection);
+
+ ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS,
+ ro_toolbar_menu_option_shade(cookies_window.toolbar));
+ ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS,
+ ro_toolbar_menu_buttons_tick(cookies_window.toolbar));
+
+ ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT,
+ ro_toolbar_menu_edit_shade(cookies_window.toolbar));
+ ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT,
+ ro_toolbar_menu_edit_tick(cookies_window.toolbar));
+
+ return true;
+}
+
+/**
+ * Handle submenu warnings for the cookies menu
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu to which the warning applies.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ */
+
+void ro_gui_cookies_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ /* Do nothing */
+}
+
+/**
+ * Handle selections from the cookies menu
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu from which the selection was made.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
+ */
+
+bool ro_gui_cookies_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ switch (action) {
+ case TREE_EXPAND_ALL:
+ cookie_manager_expand(false);
+ return true;
+ case TREE_EXPAND_FOLDERS:
+ cookie_manager_expand(true);
+ return true;
+ case TREE_EXPAND_LINKS:
+ cookie_manager_expand(false);
+ return true;
+ case TREE_COLLAPSE_ALL:
+ cookie_manager_contract(true);
+ return true;
+ case TREE_COLLAPSE_FOLDERS:
+ cookie_manager_contract(true);
+ return true;
+ case TREE_COLLAPSE_LINKS:
+ cookie_manager_contract(false);
+ return true;
+ case TREE_SELECTION_DELETE:
+ cookie_manager_keypress(NS_KEY_DELETE_LEFT);
+ return true;
+ case TREE_SELECT_ALL:
+ cookie_manager_keypress(NS_KEY_SELECT_ALL);
+ return true;
+ case TREE_CLEAR_SELECTION:
+ cookie_manager_keypress(NS_KEY_CLEAR_SELECTION);
+ return true;
+ case TOOLBAR_BUTTONS:
+ ro_toolbar_set_display_buttons(cookies_window.toolbar,
+ !ro_toolbar_get_display_buttons(
+ cookies_window.toolbar));
+ return true;
+ case TOOLBAR_EDIT:
+ ro_toolbar_toggle_edit(cookies_window.toolbar);
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+/**
+ * Check if a particular window handle is the cookies window
+ *
+ * \param window the window in question
+ * \return true if this window is the cookies
+ */
+
+bool ro_gui_cookies_check_window(wimp_w window)
+{
+ if (cookies_window.window == window)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Check if a particular menu handle is the cookies menu
+ *
+ * \param *menu The menu in question.
+ * \return true if this menu is the cookies menu
+ */
+
+bool ro_gui_cookies_check_menu(wimp_menu *menu)
+{
+ if (cookies_window.menu == menu)
+ return true;
+ else
+ return false;
+}
+
diff --git a/frontends/riscos/cookies.h b/frontends/riscos/cookies.h
new file mode 100644
index 000000000..b7313393e
--- /dev/null
+++ b/frontends/riscos/cookies.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Cookies (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_COOKIES_H_
+#define _NETSURF_RISCOS_COOKIES_H_
+
+#include "riscos/menus.h"
+
+void ro_gui_cookies_preinitialise(void);
+void ro_gui_cookies_postinitialise(void);
+void ro_gui_cookies_destroy(void);
+bool ro_gui_cookies_check_window(wimp_w window);
+bool ro_gui_cookies_check_menu(wimp_menu *menu);
+
+void ro_gui_cookies_open(void);
+
+#endif
+
diff --git a/frontends/riscos/dialog.c b/frontends/riscos/dialog.c
new file mode 100644
index 000000000..d4356086d
--- /dev/null
+++ b/frontends/riscos/dialog.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
+ * Copyright 2014 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oslib/colourtrans.h>
+#include <oslib/osfile.h>
+#include <oslib/osgbpb.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/nsurl.h"
+#include "desktop/version.h"
+#include "desktop/browser.h"
+
+#include "riscos/configure.h"
+#include "riscos/cookies.h"
+#include "riscos/dialog.h"
+#include "riscos/global_history.h"
+#include "riscos/gui.h"
+#include "riscos/hotlist.h"
+#include "riscos/menus.h"
+#include "riscos/save.h"
+#include "riscos/sslcert.h"
+#include "riscos/toolbar.h"
+#include "riscos/url_complete.h"
+#include "riscos/url_suggest.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/wimputils.h"
+
+#define ICON_ZOOM_VALUE 1
+#define ICON_ZOOM_DEC 2
+#define ICON_ZOOM_INC 3
+#define ICON_ZOOM_FRAMES 5
+#define ICON_ZOOM_CANCEL 7
+#define ICON_ZOOM_OK 8
+
+/* The maximum number of persistent dialogues
+*/
+#define MAX_PERSISTENT 64
+
+
+wimp_w dialog_info, dialog_saveas,
+ dialog_401li,
+ dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip,
+ dialog_warning,
+ dialog_folder, dialog_entry, dialog_search, dialog_print,
+ dialog_url_complete, dialog_openurl;
+
+struct gui_window *ro_gui_current_zoom_gui;
+
+
+/* A simple mapping of parent and child
+*/
+static struct {
+ wimp_w dialog;
+ wimp_w parent;
+} persistent_dialog[MAX_PERSISTENT];
+
+
+static bool ro_gui_dialog_open_url_init(void);
+static bool ro_gui_dialog_openurl_apply(wimp_w w);
+static bool ro_gui_dialog_open_url_menu_prepare(wimp_w w, wimp_i i,
+ wimp_menu *menu, wimp_pointer *pointer);
+
+static bool ro_gui_dialog_zoom_apply(wimp_w w);
+
+/**
+ * Load and create dialogs from template file.
+ */
+
+void ro_gui_dialog_init(void)
+{
+ /* warning dialog */
+ dialog_warning = ro_gui_dialog_create("warning");
+ ro_gui_wimp_event_register_ok(dialog_warning, ICON_WARNING_CONTINUE,
+ NULL);
+ ro_gui_wimp_event_set_help_prefix(dialog_warning, "HelpWarning");
+
+ /* tooltip for history */
+ dialog_tooltip = ro_gui_dialog_create("tooltip");
+
+ /* configure window */
+ ro_gui_configure_initialise();
+
+ /* 401 login window */
+ ro_gui_401login_init();
+
+ /* theme installation */
+ dialog_theme_install = ro_gui_dialog_create("theme_inst");
+ ro_gui_wimp_event_register_cancel(dialog_theme_install,
+ ICON_THEME_INSTALL_CANCEL);
+ ro_gui_wimp_event_register_ok(dialog_theme_install,
+ ICON_THEME_INSTALL_INSTALL,
+ ro_gui_theme_install_apply);
+ ro_gui_wimp_event_set_help_prefix(dialog_theme_install, "HelpThemeInst");
+
+ /* search */
+ ro_gui_search_init();
+
+ /* print */
+ ro_gui_print_init();
+
+ /* about us */
+ dialog_info = ro_gui_dialog_create("info");
+ ro_gui_set_icon_string(dialog_info, 4, netsurf_version, true);
+ ro_gui_wimp_event_set_help_prefix(dialog_info, "HelpAppInfo");
+
+ /* page info */
+ dialog_pageinfo = ro_gui_dialog_create("pageinfo");
+ ro_gui_wimp_event_set_help_prefix(dialog_pageinfo, "HelpPageInfo");
+
+ /* object info */
+ dialog_objinfo = ro_gui_dialog_create("objectinfo");
+ ro_gui_wimp_event_set_help_prefix(dialog_objinfo, "HelpObjInfo");
+
+ /* save as */
+ dialog_saveas = ro_gui_saveas_create("saveas");
+ ro_gui_wimp_event_register_button(dialog_saveas, ICON_SAVE_ICON,
+ ro_gui_save_start_drag);
+ ro_gui_wimp_event_register_text_field(dialog_saveas, ICON_SAVE_PATH);
+ ro_gui_wimp_event_register_cancel(dialog_saveas, ICON_SAVE_CANCEL);
+ ro_gui_wimp_event_register_ok(dialog_saveas, ICON_SAVE_OK,
+ ro_gui_save_ok);
+ ro_gui_wimp_event_set_help_prefix(dialog_saveas, "HelpSaveAs");
+
+ /* url suggestion */
+ dialog_url_complete = ro_gui_dialog_create("url_suggest");
+ ro_gui_wimp_event_register_mouse_click(dialog_url_complete,
+ ro_gui_url_complete_click);
+ ro_gui_wimp_event_register_pointer_entering_window(dialog_url_complete,
+ ro_gui_url_complete_entering);
+ ro_gui_wimp_event_register_redraw_window(dialog_url_complete,
+ ro_gui_url_complete_redraw);
+ ro_gui_wimp_event_set_help_prefix(dialog_url_complete, "HelpAutoURL");
+
+ /* open URL */
+ ro_gui_dialog_open_url_init();
+
+ /* scale view */
+ dialog_zoom = ro_gui_dialog_create("zoom");
+ ro_gui_wimp_event_register_numeric_field(dialog_zoom, ICON_ZOOM_VALUE,
+ ICON_ZOOM_INC, ICON_ZOOM_DEC, 10, 1600, 10, 0);
+ ro_gui_wimp_event_register_checkbox(dialog_zoom, ICON_ZOOM_FRAMES);
+ ro_gui_wimp_event_register_cancel(dialog_zoom, ICON_ZOOM_CANCEL);
+ ro_gui_wimp_event_register_ok(dialog_zoom, ICON_ZOOM_OK,
+ ro_gui_dialog_zoom_apply);
+ ro_gui_wimp_event_set_help_prefix(dialog_zoom, "HelpScaleView");
+
+ /* Treeview initialisation has moved to the end, to allow any
+ * associated dialogues to be set up first.
+ */
+
+ /* certificate verification window */
+ ro_gui_cert_preinitialise();
+
+ /* hotlist window */
+ ro_gui_hotlist_preinitialise();
+
+ /* global history window */
+ ro_gui_global_history_preinitialise();
+
+ /* cookies window */
+ ro_gui_cookies_preinitialise();
+}
+
+
+/**
+ * Create a window from a template.
+ *
+ * \param template_name name of template to load
+ * \return window handle
+ *
+ * Exits through die() on error.
+ */
+
+wimp_w ro_gui_dialog_create(const char *template_name)
+{
+ wimp_window *window;
+ wimp_w w;
+ os_error *error;
+
+ window = ro_gui_dialog_load_template(template_name);
+
+ /* create window */
+ window->sprite_area = gui_sprites;
+ error = xwimp_create_window(window, &w);
+ if (error) {
+ LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ xwimp_close_template();
+ die(error->errmess);
+ }
+
+ /* the window definition is copied by the wimp and may be freed */
+ free(window);
+
+ return w;
+}
+
+
+/**
+ * Load a template without creating a window.
+ *
+ * \param template_name name of template to load
+ * \return window block
+ *
+ * Exits through die() on error.
+ */
+
+wimp_window * ro_gui_dialog_load_template(const char *template_name)
+{
+ char name[20];
+ int context, window_size, data_size;
+ char *data;
+ wimp_window *window;
+ os_error *error;
+
+ /* Template names must be <= 11 chars long */
+ assert(strlen(template_name) <= 11);
+
+ /* wimp_load_template won't accept a const char * */
+ strncpy(name, template_name, sizeof name);
+
+ /* find required buffer sizes */
+ error = xwimp_load_template(wimp_GET_SIZE, 0, 0, wimp_NO_FONTS,
+ name, 0, &window_size, &data_size, &context);
+ if (error) {
+ LOG("xwimp_load_template: 0x%x: %s", error->errnum, error->errmess);
+ xwimp_close_template();
+ die(error->errmess);
+ }
+ if (!context) {
+ LOG("template '%s' missing", template_name);
+ xwimp_close_template();
+ die("Template");
+ }
+
+ /* allocate space for indirected data and temporary window buffer */
+ data = malloc(data_size);
+ window = malloc(window_size);
+ if (!data || !window) {
+ xwimp_close_template();
+ die("NoMemory");
+ }
+
+ /* load template */
+ error = xwimp_load_template(window, data, data + data_size,
+ wimp_NO_FONTS, name, 0, 0, 0, 0);
+ if (error) {
+ LOG("xwimp_load_template: 0x%x: %s", error->errnum, error->errmess);
+ xwimp_close_template();
+ die(error->errmess);
+ }
+
+ return window;
+}
+
+
+/**
+ * Open a dialog box, centred on the screen.
+ */
+
+void ro_gui_dialog_open(wimp_w w)
+{
+ int screen_x, screen_y, dx, dy;
+ wimp_window_state state;
+ os_error *error;
+
+ /* find screen centre in os units */
+ ro_gui_screen_size(&screen_x, &screen_y);
+ screen_x /= 2;
+ screen_y /= 2;
+
+ /* centre and open */
+ state.w = w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ dx = (state.visible.x1 - state.visible.x0) / 2;
+ dy = (state.visible.y1 - state.visible.y0) / 2;
+ state.visible.x0 = screen_x - dx;
+ state.visible.x1 = screen_x + dx;
+ state.visible.y0 = screen_y - dy;
+ state.visible.y1 = screen_y + dy;
+ state.next = wimp_TOP;
+ ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
+
+ /* Set the caret position */
+ ro_gui_set_caret_first(w);
+}
+
+
+/**
+ * Close a dialog box.
+ */
+
+void ro_gui_dialog_close(wimp_w close)
+{
+ int i;
+ wimp_caret caret;
+ os_error *error;
+
+ /* Check if we're a persistent window */
+ for (i = 0; i < MAX_PERSISTENT; i++) {
+ if (persistent_dialog[i].dialog == close) {
+ /* We are => invalidate record */
+ persistent_dialog[i].parent = NULL;
+ persistent_dialog[i].dialog = NULL;
+ break;
+ }
+ }
+
+ /* Close any child windows */
+ ro_gui_dialog_close_persistent(close);
+
+ /* Give the caret back to the parent window. This code relies on
+ the fact that only tree windows and browser windows open
+ persistent dialogues, as the caret gets placed to no icon.
+ */
+ error = xwimp_get_caret_position(&caret);
+ if (error) {
+ LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ } else if (caret.w == close) {
+ /* Check if we are a persistent window */
+ if (i < MAX_PERSISTENT) {
+ error = xwimp_set_caret_position(
+ persistent_dialog[i].parent,
+ wimp_ICON_WINDOW, -100, -100,
+ 32, -1);
+ /* parent may have been closed first */
+ if ((error) && (error->errnum != 0x287)) {
+ LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+ }
+
+ error = xwimp_close_window(close);
+ if (error) {
+ LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+}
+
+
+/**
+ * Moves a window to the top of the stack.
+ *
+ * If the window is currently closed then:
+ *
+ * * The window is opened in the centre of the screen (at the supplied size)
+ * * Any toolbar editing session is stopped
+ * * The scroll position is set to the top of the window
+ *
+ * If the window is currently open then:
+ *
+ * * The window is brought to the top of the stack
+ *
+ * \param w the window to show
+ * \param toolbar the toolbar to consider
+ * \param width the window width if it is currently closed (or 0 to retain)
+ * \param height the window height if it is currently closed (or 0 to retain)
+ * \return true if the window was previously open
+ */
+bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
+ int width, int height) {
+ os_error *error;
+ int screen_width, screen_height;
+ wimp_window_state state;
+ bool open;
+
+ state.w = w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
+
+ /* if we're open we jump to the top of the stack, if not then we
+ * open in the centre of the screen. */
+ open = state.flags & wimp_WINDOW_OPEN;
+ if (!open) {
+ int dimension;
+ int scroll_width;
+ /* cancel any editing */
+ if (ro_toolbar_get_editing(toolbar))
+ ro_toolbar_toggle_edit(toolbar);
+
+ /* move to the centre */
+ ro_gui_screen_size(&screen_width, &screen_height);
+ dimension = ((width == 0) ?
+ (state.visible.x1 - state.visible.x0) : width);
+ scroll_width = ro_get_vscroll_width(w);
+ state.visible.x0 = (screen_width - (dimension + scroll_width)) / 2;
+ state.visible.x1 = state.visible.x0 + dimension;
+ dimension = ((height == 0) ?
+ (state.visible.y1 - state.visible.y0) : height);
+ state.visible.y0 = (screen_height - dimension) / 2;
+ state.visible.y1 = state.visible.y0 + dimension;
+ state.xscroll = 0;
+ state.yscroll = 0;
+ if (toolbar)
+ state.yscroll = ro_toolbar_height(toolbar);
+ }
+
+ /* open the window at the top of the stack */
+ state.next = wimp_TOP;
+ ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
+ return open;
+}
+
+
+/**
+ * Open window at the location of the pointer.
+ */
+
+void ro_gui_dialog_open_at_pointer(wimp_w w)
+{
+ wimp_pointer ptr;
+ os_error *error;
+
+ /* get the pointer position */
+ error = xwimp_get_pointer_info(&ptr);
+ if (error) {
+ LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ ro_gui_dialog_open_xy(w, ptr.pos.x - 64, ptr.pos.y);
+}
+
+
+/**
+ * Open window at a specified location.
+ */
+
+void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
+{
+ wimp_window_state state;
+ os_error *error;
+ int dx, dy;
+
+ /* move the window */
+ state.w = w;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ dx = (state.visible.x1 - state.visible.x0);
+ dy = (state.visible.y1 - state.visible.y0);
+ state.visible.x0 = x;
+ state.visible.x1 = x + dx;
+ state.visible.y0 = y - dy;
+ state.visible.y1 = y;
+
+ /* if the window is already open, close it first so that it opens fully
+ * on screen */
+ error = xwimp_close_window(w);
+ if (error) {
+ LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ /* open the window at the top of the stack */
+ state.next = wimp_TOP;
+ ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
+}
+
+
+/**
+ * Opens a window at the centre of either another window or the screen
+ *
+ * /param parent the parent window (NULL for centre of screen)
+ * /param child the child window
+ */
+void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
+ os_error *error;
+ wimp_window_state state;
+ int mid_x, mid_y;
+ int dimension, scroll_width;
+
+ /* get the parent window state */
+ if (parent) {
+ state.w = parent;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ scroll_width = ro_get_vscroll_width(parent);
+ mid_x = (state.visible.x0 + state.visible.x1 + scroll_width);
+ mid_y = (state.visible.y0 + state.visible.y1);
+ } else {
+ ro_gui_screen_size(&mid_x, &mid_y);
+ }
+ mid_x /= 2;
+ mid_y /= 2;
+
+ /* get the child window state */
+ state.w = child;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ /* move to the centre of the parent at the top of the stack */
+ dimension = state.visible.x1 - state.visible.x0;
+ scroll_width = ro_get_vscroll_width(history_window);
+ state.visible.x0 = mid_x - (dimension + scroll_width) / 2;
+ state.visible.x1 = state.visible.x0 + dimension;
+ dimension = state.visible.y1 - state.visible.y0;
+ state.visible.y0 = mid_y - dimension / 2;
+ state.visible.y1 = state.visible.y0 + dimension;
+ state.next = wimp_TOP;
+ ro_gui_open_window_request(PTR_WIMP_OPEN(&state));
+}
+
+
+/**
+ * Open a persistent dialog box relative to the pointer.
+ *
+ * \param parent the owning window (NULL for no owner)
+ * \param w the dialog window
+ * \param pointer open the window at the pointer (centre of the parent
+ * otherwise)
+ */
+
+void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer) {
+
+ if (pointer)
+ ro_gui_dialog_open_at_pointer(w);
+ else
+ ro_gui_dialog_open_centre_parent(parent, w);
+
+ /* todo: use wimp_event definitions rather than special cases */
+ if ((w == dialog_pageinfo) || (w == dialog_objinfo))
+ ro_gui_wimp_update_window_furniture(w, wimp_WINDOW_CLOSE_ICON,
+ wimp_WINDOW_CLOSE_ICON);
+ ro_gui_dialog_add_persistent(parent, w);
+ ro_gui_set_caret_first(w);
+}
+
+
+void ro_gui_dialog_add_persistent(wimp_w parent, wimp_w w) {
+ int i;
+
+ /* all persistant windows have a back icon */
+ ro_gui_wimp_update_window_furniture(w, wimp_WINDOW_BACK_ICON,
+ wimp_WINDOW_BACK_ICON);
+
+ /* Add a mapping
+ */
+ if ((parent == NULL) || (parent == wimp_ICON_BAR))
+ return;
+ for (i = 0; i < MAX_PERSISTENT; i++) {
+ if (persistent_dialog[i].dialog == NULL ||
+ persistent_dialog[i].dialog == w) {
+ persistent_dialog[i].dialog = w;
+ persistent_dialog[i].parent = parent;
+ return;
+ }
+ }
+ LOG("Unable to map persistent dialog to parent.");
+ return;
+}
+
+
+/**
+ * Close persistent dialogs associated with a window.
+ *
+ * \param parent the window to close children of
+ */
+
+void ro_gui_dialog_close_persistent(wimp_w parent) {
+ int i;
+ wimp_w w;
+
+ /* Check our mappings.
+ *
+ * The window handle is copied into w before proceeding, as
+ * ro_gui_dialog_close() will NULL persistent_dialog[i].dialog as
+ * part of the closing process. This would mean that the subsequent
+ * event dispatch would fail. (These events are logged to allow
+ * side effects to be investigated -- this code hasn't worked before).
+ */
+ for (i = 0; i < MAX_PERSISTENT; i++) {
+ if (persistent_dialog[i].parent == parent &&
+ persistent_dialog[i].dialog != NULL) {
+ w = persistent_dialog[i].dialog;
+ ro_gui_dialog_close(w);
+ if (ro_gui_wimp_event_close_window(w))
+ LOG("Persistent dialog close event: 0x%x", (unsigned)w);
+ persistent_dialog[i].parent = NULL;
+ persistent_dialog[i].dialog = NULL;
+ }
+ }
+}
+
+
+/**
+ * Save the current options.
+ */
+
+void ro_gui_save_options(void)
+{
+ nsoption_write("<NetSurf$ChoicesSave>", NULL, NULL);
+}
+
+bool ro_gui_dialog_zoom_apply(wimp_w w) {
+ unsigned int scale;
+ bool all;
+
+ scale = atoi(ro_gui_get_icon_string(w, ICON_ZOOM_VALUE));
+ all = ro_gui_get_icon_selected_state(w, ICON_ZOOM_FRAMES);
+ ro_gui_window_set_scale(ro_gui_current_zoom_gui, scale * 0.01);
+ return true;
+}
+
+
+/**
+ * Prepares the Scale view dialog.
+ */
+
+void ro_gui_dialog_prepare_zoom(struct gui_window *g)
+{
+ char scale_buffer[8];
+ sprintf(scale_buffer, "%.0f", browser_window_get_scale(g->bw) * 100);
+ ro_gui_set_icon_string(dialog_zoom, ICON_ZOOM_VALUE, scale_buffer, true);
+ ro_gui_set_icon_selected_state(dialog_zoom, ICON_ZOOM_FRAMES, true);
+ ro_gui_set_icon_shaded_state(dialog_zoom, ICON_ZOOM_FRAMES, true);
+ ro_gui_current_zoom_gui = g;
+ ro_gui_wimp_event_memorise(dialog_zoom);
+}
+
+/**
+ * Update the Scale View dialog to reflect the current window settings
+ *
+ * \param g the gui_window to update for
+ */
+void ro_gui_dialog_update_zoom(struct gui_window *g) {
+ if (g == ro_gui_current_zoom_gui)
+ ro_gui_dialog_prepare_zoom(g);
+}
+
+
+/**
+ * Create the Open URL dialogue, allocating storage for the URL field icon
+ * as we go.
+ *
+ * \return true on success; false on failure (although errors with
+ * the templates or memory allocation will exit via die()).
+ */
+
+static bool ro_gui_dialog_open_url_init(void)
+{
+ wimp_window *definition;
+ char *buffer;
+ os_error *error;
+
+ definition = ro_gui_dialog_load_template("open_url");
+
+ /* _load_template() should die on any error, so we trust its data. */
+
+ assert(definition != NULL);
+
+ /* Create the dialogue, with modifications. */
+
+ if ((definition->icons[ICON_OPENURL_URL].flags & wimp_ICON_INDIRECTED)
+ == 0) {
+ LOG("open_url URL icon not indirected");
+ xwimp_close_template();
+ die("Template");
+ }
+
+ buffer = malloc(RO_GUI_MAX_URL_SIZE);
+ if (buffer == NULL) {
+ xwimp_close_template();
+ die("NoMemory");
+ }
+
+ definition->icons[ICON_OPENURL_URL].data.indirected_text.text = buffer;
+ definition->icons[ICON_OPENURL_URL].data.indirected_text.size =
+ RO_GUI_MAX_URL_SIZE;
+ definition->sprite_area = gui_sprites;
+
+ error = xwimp_create_window(definition, &dialog_openurl);
+ if (error != NULL) {
+ LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ xwimp_close_template();
+ die(error->errmess);
+ }
+
+ free(definition);
+
+ ro_gui_wimp_event_register_menu_gright(dialog_openurl, ICON_OPENURL_URL,
+ ICON_OPENURL_MENU, ro_gui_url_suggest_menu);
+ ro_gui_wimp_event_register_cancel(dialog_openurl, ICON_OPENURL_CANCEL);
+ ro_gui_wimp_event_register_ok(dialog_openurl, ICON_OPENURL_OPEN,
+ ro_gui_dialog_openurl_apply);
+ ro_gui_wimp_event_register_menu_prepare(dialog_openurl,
+ ro_gui_dialog_open_url_menu_prepare);
+ ro_gui_wimp_event_set_help_prefix(dialog_openurl, "HelpOpenURL");
+
+ return true;
+}
+
+
+
+bool ro_gui_dialog_openurl_apply(wimp_w w) {
+ const char *urltxt;
+ char *url2;
+ nsurl *url;
+ nserror error;
+
+ urltxt = ro_gui_get_icon_string(w, ICON_OPENURL_URL);
+ url2 = strdup(urltxt); /** @todo why is this copied */
+ if (url2 == NULL) {
+ return false;
+ }
+
+ error = nsurl_create(url2, &url);
+ free(url2);
+ if (error == NSERROR_OK) {
+ error = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ return false;
+ }
+
+ return true;
+
+}
+
+
+/**
+ * Prepares the Open URL dialog.
+ */
+
+void ro_gui_dialog_prepare_open_url(void)
+{
+ ro_gui_set_icon_string(dialog_openurl, ICON_OPENURL_URL, "", true);
+ ro_gui_set_icon_shaded_state(dialog_openurl,
+ ICON_OPENURL_MENU, !ro_gui_url_suggest_prepare_menu());
+ ro_gui_wimp_event_memorise(dialog_openurl);
+}
+
+
+/**
+ * Callback to prepare menus in the Open URL dialog. At present, this
+ * only has to handle the URL Suggestion pop-up.
+ *
+ * \param w The window handle owning the menu.
+ * \param i The icon handle owning the menu.
+ * \param *menu The menu to be prepared.
+ * \param *pointer The associated mouse click event block, or NULL
+ * on an Adjust-click re-opening.
+ * \return true if the event was handled; false if not.
+ */
+
+bool ro_gui_dialog_open_url_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_pointer *pointer)
+{
+ if (menu != ro_gui_url_suggest_menu || i != ICON_OPENURL_MENU)
+ return false;
+
+ if (pointer != NULL)
+ return ro_gui_url_suggest_prepare_menu();
+
+ return true;
+}
diff --git a/frontends/riscos/dialog.h b/frontends/riscos/dialog.h
new file mode 100644
index 000000000..463048436
--- /dev/null
+++ b/frontends/riscos/dialog.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_RISCOS_DIALOG_H_
+#define _NETSURF_RISCOS_DIALOG_H_
+
+struct toolbar;
+struct gui_window;
+
+void ro_gui_dialog_init(void);
+wimp_w ro_gui_dialog_create(const char *template_name);
+wimp_window * ro_gui_dialog_load_template(const char *template_name);
+
+void ro_gui_dialog_open(wimp_w w);
+void ro_gui_dialog_close(wimp_w close);
+
+bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
+ int width, int height);
+void ro_gui_dialog_open_at_pointer(wimp_w w);
+void ro_gui_dialog_open_xy(wimp_w, int x, int y);
+void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w w);
+
+void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer);
+void ro_gui_dialog_add_persistent(wimp_w parent, wimp_w w);
+void ro_gui_dialog_close_persistent(wimp_w parent);
+
+
+
+
+void ro_gui_dialog_click(wimp_pointer *pointer);
+void ro_gui_dialog_prepare_zoom(struct gui_window *g);
+void ro_gui_dialog_update_zoom(struct gui_window *g);
+void ro_gui_dialog_prepare_open_url(void);
+void ro_gui_save_options(void);
+void ro_gui_dialog_open_config(void);
+void ro_gui_dialog_proxyauth_menu_selection(int item);
+void ro_gui_dialog_image_menu_selection(int item);
+void ro_gui_dialog_languages_menu_selection(const char *lang);
+void ro_gui_dialog_font_menu_selection(int item);
+#endif
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!Boot,feb b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Boot,feb
new file mode 100644
index 000000000..485bd521d
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Boot,feb
@@ -0,0 +1,17 @@
+If (("<Cache$AppDir>" = "") OR ("<Cache$ForceVars>" = "1")) Then Set Cache$AppDir <Obey$Dir>
+
+IconSprites <Cache$AppDir>.!Sprites
+
+| Find and set up resource paths
+WimpSlot -min 64k -max 64k
+Run <Cache$AppDir>.Resources.ResFind CacheApp
+If (("<Cache$Meta>" = "") OR ("<Cache$ForceVars>" = "1")) Then Set Cache$Meta CacheAppRes:!Meta
+
+| Work out where the cache directory should be -- use Choices$User if set or Default, otherwise.
+Set Cache$Suffix "<Choices$User>"
+If "<Cache$Suffix>" = "" Then Set Cache$Suffix "Default"
+If (("<Cache$Dir>" = "") OR ("<Cache$ForceVars>" = "1")) Then Set Cache$Dir "<Cache$AppDir>.Caches.<Cache$Suffix>"
+Unset Cache$Suffix
+
+| Ensure cache directory exists (sadly, unavoidable)
+CDir <Cache$Dir>
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!Help,feb b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Help,feb
new file mode 100644
index 000000000..35eeeb31b
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Help,feb
@@ -0,0 +1,2 @@
+If "<CacheAppRes$Path>" = "" Then Run <Cache$AppDir>.Resources.ResFind CacheApp
+Filer_Run CacheAppRes:Help \ No newline at end of file
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!Run,feb b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Run,feb
new file mode 100644
index 000000000..8aead9733
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Run,feb
@@ -0,0 +1,9 @@
+Set Cache$ForceVars 1
+Run <Obey$Dir>.!Boot
+Unset Cache$ForceVars
+
+RMEnsure SysLog 0.17 IfThere <SysLog$Dir>.!Run Then Run <SysLog$Dir>.!Run
+RMEnsure SysLog 0.17 Set Cache$SysLogMissing "True"
+
+Wimpslot -min 128k -max 128k
+Run <Cache$AppDir>.!RunImage
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!RunImage,ffb b/frontends/riscos/distribution/!Boot/Resources/!Cache/!RunImage,ffb
new file mode 100644
index 000000000..61752af99
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!RunImage,ffb
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites,ff9 b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites,ff9
new file mode 100644
index 000000000..b71a51cf3
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites,ff9
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites22,ff9 b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites22,ff9
new file mode 100644
index 000000000..e43f88c89
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/!Sprites22,ff9
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Caches/Blank b/frontends/riscos/distribution/!Boot/Resources/!Cache/Caches/Blank
new file mode 100644
index 000000000..898dc5872
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Caches/Blank
@@ -0,0 +1 @@
+This is here just to stop the directory structure getting lost when unzipping. \ No newline at end of file
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/MultiError,ffb b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/MultiError,ffb
new file mode 100644
index 000000000..ec348b0e9
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/MultiError,ffb
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/ResFind,ffb b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/ResFind,ffb
new file mode 100644
index 000000000..7766cc928
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/ResFind,ffb
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/!Meta b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/!Meta
new file mode 100644
index 000000000..2de40bd7c
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/!Meta
@@ -0,0 +1,9 @@
+# Meta file for Cache
+Help:<CacheAppRes$Dir>.Help
+Version:1.13
+Web:http://www.snowstone.org.uk/riscos/
+Title:Cache
+Publisher:Adam Richardson
+Description:Cache provides a central location for semi-permanent data on your system.
+Email:riscos@snowstone.org.uk
+
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Help b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Help
new file mode 100644
index 000000000..aad9bf0b1
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Help
@@ -0,0 +1,60 @@
+Cache
+-----
+
+Cache provides a shared location for cached data. This location can be
+used by application authors to store semi-permanent data. Cache can be
+placed anywhere on your computer where it will be "seen" by the Filer
+during start up. (For instance, the "Resources" directory inside !Boot.)
+
+Once "seen" it will set up a cache location, which can be shown by
+double-clicking on !Cache.
+
+
+Application Authors
+----------- -------
+
+Use Cache in a similar way to using Scrap. You *must not* assume that
+Cache is present on the user's system however, as Cache is not an
+official part of the system (like Scrap).
+
+To use Cache you should:
+ * Check for the presence of "<Cache$Dir>" before proceeding
+ * Read from and write data to "<Cache$Dir>.APPNAME" where APPNAME has
+ been allocated to you by the allocations service. See:
+ http://www.riscosopen.com/content/allocate
+ * If the APPNAME directory does not exist, you should create it.
+
+This version of Cache is published by Adam Richardson who can be
+contacted at riscos@snowstone.org.uk.
+
+The website for Cache is: http://www.snowstone.org.uk/riscos/
+
+
+Credits
+-------
+
+Cache is (c) Adam Richardson, 2007.
+Thanks to Rob Kendrick for the initial idea and input.
+
+
+License
+-------
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Messages b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Messages
new file mode 100644
index 000000000..366122292
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Messages
@@ -0,0 +1,8 @@
+# Messages for Cache
+
+multiuser:Multi-user system present.
+singleuser:No multi-user system present.
+location:Cache directory set to:
+opendir:Opening cache location...
+fatalerror:Cache has suffered a fatal error and has quit.
+
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Templates,fec b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Templates,fec
new file mode 100644
index 000000000..22f910ad9
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Cache/Resources/UK/Templates,fec
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Boot,feb b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Boot,feb
new file mode 100644
index 000000000..7c0c46241
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Boot,feb
@@ -0,0 +1,5 @@
+| Unicode Boot file
+|
+Set Unicode$Dir <Obey$Dir>
+SetMacro Unicode$Path <Unicode$Dir>.,Resources:$.Resources.Unicode.
+IconSprites Unicode:!Sprites
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Help b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Help
new file mode 100644
index 000000000..8c0488185
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Help
@@ -0,0 +1 @@
+This application contains resources for Unicode support in applications.
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Run,feb b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Run,feb
new file mode 100644
index 000000000..bd70e96ac
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Run,feb
@@ -0,0 +1,5 @@
+| Unicode Run file
+|
+Set Unicode$Dir <Obey$Dir>
+SetMacro Unicode$Path <Unicode$Dir>.,Resources:$.Resources.Unicode.
+IconSprites Unicode:!Sprites
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites,ff9 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites,ff9
new file mode 100644
index 000000000..3eb5b44b7
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites,ff9
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites11,ff9 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites11,ff9
new file mode 100644
index 000000000..48986b41e
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites11,ff9
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites22,ff9 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites22,ff9
new file mode 100644
index 000000000..63a6e6122
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/!Sprites22,ff9
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Acorn/Latin1 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Acorn/Latin1
new file mode 100644
index 000000000..bdf5d3b67
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Acorn/Latin1
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/CentEuro b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/CentEuro
new file mode 100644
index 000000000..5ab69ff2e
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/CentEuro
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Cyrillic b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Cyrillic
new file mode 100644
index 000000000..670fd6cdc
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Cyrillic
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Roman b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Roman
new file mode 100644
index 000000000..254579e2c
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Roman
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Ukrainian b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Ukrainian
new file mode 100644
index 000000000..a220587ba
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Apple/Ukrainian
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/BigFive b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/BigFive
new file mode 100644
index 000000000..c659cef19
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/BigFive
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C0/40[ISO646] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C0/40[ISO646]
new file mode 100644
index 000000000..cd92b5486
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C0/40[ISO646]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C1/43[IS6429] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C1/43[IS6429]
new file mode 100644
index 000000000..74002a168
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/C1/43[IS6429]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/40[646old] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/40[646old]
new file mode 100644
index 000000000..00e2d1096
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/40[646old]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/41[646-GB] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/41[646-GB]
new file mode 100644
index 000000000..c293f93d6
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/41[646-GB]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/42[646IRV] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/42[646IRV]
new file mode 100644
index 000000000..e0b4bcadb
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/42[646IRV]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/43[FinSwe] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/43[FinSwe]
new file mode 100644
index 000000000..7d4646905
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/43[FinSwe]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/47[646-SE] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/47[646-SE]
new file mode 100644
index 000000000..a6b091a22
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/47[646-SE]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/48[646-SE] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/48[646-SE]
new file mode 100644
index 000000000..9bd24ab29
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/48[646-SE]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/49[JS201K] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/49[JS201K]
new file mode 100644
index 000000000..20ce8d498
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/49[JS201K]
@@ -0,0 +1 @@
+a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я                                                                \ No newline at end of file
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4A[JS201R] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4A[JS201R]
new file mode 100644
index 000000000..21d2a479b
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4A[JS201R]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4B[646-DE] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4B[646-DE]
new file mode 100644
index 000000000..a2e284e1b
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4B[646-DE]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4C[646-PT] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4C[646-PT]
new file mode 100644
index 000000000..e076e2517
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/4C[646-PT]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/54[GB1988] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/54[GB1988]
new file mode 100644
index 000000000..3b43719ce
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/54[GB1988]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/56[Teltxt] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/56[Teltxt]
new file mode 100644
index 000000000..73ce49e17
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/56[Teltxt]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/59[646-IT] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/59[646-IT]
new file mode 100644
index 000000000..f1ae81962
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/59[646-IT]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/5A[646-ES] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/5A[646-ES]
new file mode 100644
index 000000000..674fc2d70
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/5A[646-ES]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/60[646-NO] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/60[646-NO]
new file mode 100644
index 000000000..fc92892ee
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/60[646-NO]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/66[646-FR] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/66[646-FR]
new file mode 100644
index 000000000..8dd604679
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/66[646-FR]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/69[646-HU] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/69[646-HU]
new file mode 100644
index 000000000..65300b2c5
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/69[646-HU]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6B[Arabic] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6B[Arabic]
new file mode 100644
index 000000000..c47689914
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6B[Arabic]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6C[IS6937] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6C[IS6937]
new file mode 100644
index 000000000..93453f5de
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/6C[IS6937]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/7A[SerbCr] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/7A[SerbCr]
new file mode 100644
index 000000000..9740e784e
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94/7A[SerbCr]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/40[JS6226] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/40[JS6226]
new file mode 100644
index 000000000..a677dfc3d
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/40[JS6226]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/41[GB2312] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/41[GB2312]
new file mode 100644
index 000000000..679608ad2
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/41[GB2312]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/42[JIS208] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/42[JIS208]
new file mode 100644
index 000000000..532b1f4f3
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/42[JIS208]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/43[KS1001] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/43[KS1001]
new file mode 100644
index 000000000..36186c864
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/43[KS1001]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/44[JIS212] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/44[JIS212]
new file mode 100644
index 000000000..f5343a30e
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/44[JIS212]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/47[CNS1] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/47[CNS1]
new file mode 100644
index 000000000..da07f45d3
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/47[CNS1]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/48[CNS2] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/48[CNS2]
new file mode 100644
index 000000000..44ee24c91
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/48[CNS2]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/49[CNS3] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/49[CNS3]
new file mode 100644
index 000000000..a8464e5aa
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/49[CNS3]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4A[CNS4] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4A[CNS4]
new file mode 100644
index 000000000..a8f3e3270
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4A[CNS4]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4B[CNS5] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4B[CNS5]
new file mode 100644
index 000000000..535b0f4b5
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4B[CNS5]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4C[CNS6] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4C[CNS6]
new file mode 100644
index 000000000..7bfb2b1d4
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4C[CNS6]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4D[CNS7] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4D[CNS7]
new file mode 100644
index 000000000..be14c7279
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G94x94/4D[CNS7]
@@ -0,0 +1,2 @@
+                                                                                          Ў5                                        UV            g6                                                                                                                                                                                                        a                    Т9                                                      E:                                                                                                        ╔;                                                                                                                                                              U=                                                                                                      ш>                                                                ╢?      ╜?                                                                          ╓@                          qA                                                                        ШB                                                                                                                                                                                                                                                                                                                                            ═E                                                                                                            ЎF                                                    zG            ╕G                                H                                                                                                                                              /I          1I              ЬI                          цI                                                                                                                                  8K                                                                                                  :L    ▒L                                                                  GM  QM                                                                                                                                                                              G7                                                            8                            г8                                                                                                                                                                                        ;                                                                                                                                                                    ╫q                                                                        Ъ>                                                              ┬?                                                                    ▄@                                          │A                                                                                                                                                                                                                                                                                                                                                          fЖ                                  ┘E  ▌E                                                                                                          №F                                                                                                                                    :П                                                                  I                            =У                              иI                                                                                                                      ╩J                                                                                                        НK                                                                  └L            ╩L                    %M                JM  SM                                                                                          6                                                                                                                                                                                                                                                      Ё;                                                                                            >            #>                                                                                                                                                                                                                  C                                                                                                                                                                            ]E                                                                            ZF                                                                                                              ЕG                                                                                                                         I            9I      7I                                                                                                                kJ                                    ═J                                                                                                                          ML                                                                                                      5                                {6                                      8                                                          їd                                      ';                                                                                                                                                            ╧?      ═?                                                                ВA                                RB                                                                  А                                                                QD                                      ZE                                                                                                                                              eF                                                                                              Н                                                                        пH                                                              AI                                                            )J              *J                                            ЦJ            K                                                                                                                                                                                                                                                                  ~6сX                                                                                                                                        з9                                                           C                                                                                                                                                                                                                    щ|                                                                        ╦Б                                                                                                        eE                                                                                              G                                                      dG                                          #H                                                                                                                                            ┘Х                                                                                                                                                                                                                                                                                                                                                                                ╣4                                                                                                                                    K<                                                                                                                  ё@                                                                                                                                                                                                                                                                        gF                      G                                                                        ЙH                                                                                                                                                                                                                                                                 L      L                                  mL  pL                            эL                                                                        НM                        з4                                                                                                g                                                                      Z>                                                                                        пB                                                                                          kE                                                                              G                                                                                                          cI                                                    АJДJJ                    ёJ                                                            GЪ                                                                                                          M                                                                    и4                                                                                                                                                                                          ЛA                      +C                                                  zE                                 F                        mF          G                                                                                            jIlI                                                                                                      ▓K                        L      -L                                                                                          EM                                                                                                                                                                                                                                                                                                                        
+F         F                                      .H                                                                                                                                                                                                              НL                                                                                                                                                                                                                          1C                                                                                                                                                                              ╝K╗K                                                                                                                                                                                                                                                                                                                  L                                                                    6          r7                                                                                                                                                                                              M                                                                                                                                                                                                                                                tv                                                                    ьK                                                                                                                                          yB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               \ No newline at end of file
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/41[Lat1] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/41[Lat1]
new file mode 100644
index 000000000..97e6b1106
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/41[Lat1]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/42[Lat2] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/42[Lat2]
new file mode 100644
index 000000000..b753c40fe
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/42[Lat2]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/43[Lat3] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/43[Lat3]
new file mode 100644
index 000000000..88d477886
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/43[Lat3]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/44[Lat4] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/44[Lat4]
new file mode 100644
index 000000000..a40662d45
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/44[Lat4]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/46[Greek] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/46[Greek]
new file mode 100644
index 000000000..c42397388
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/46[Greek]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/47[Arabic] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/47[Arabic]
new file mode 100644
index 000000000..4507f467a
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/47[Arabic]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/48[Hebrew] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/48[Hebrew]
new file mode 100644
index 000000000..70f39cca6
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/48[Hebrew]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4C[Cyrill] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4C[Cyrill]
new file mode 100644
index 000000000..8ff0115e4
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4C[Cyrill]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4D[Lat5] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4D[Lat5]
new file mode 100644
index 000000000..6381e607e
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/4D[Lat5]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/50[LatSup] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/50[LatSup]
new file mode 100644
index 000000000..a320c7fe8
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/50[LatSup]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/52[IS6937] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/52[IS6937]
new file mode 100644
index 000000000..dff6ccba4
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/52[IS6937]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/54[Thai] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/54[Thai]
new file mode 100644
index 000000000..d74377759
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/54[Thai]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/56[Lat6] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/56[Lat6]
new file mode 100644
index 000000000..4e3e4f313
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/56[Lat6]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/58[L6Sami] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/58[L6Sami]
new file mode 100644
index 000000000..4dfd9188c
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/58[L6Sami]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/59[Lat7] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/59[Lat7]
new file mode 100644
index 000000000..256a88e76
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/59[Lat7]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5C[Welsh] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5C[Welsh]
new file mode 100644
index 000000000..b5e00509f
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5C[Welsh]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5D[Sami] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5D[Sami]
new file mode 100644
index 000000000..15734c036
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5D[Sami]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5E[Hebrew] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5E[Hebrew]
new file mode 100644
index 000000000..a6593b071
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5E[Hebrew]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5F[Lat8] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5F[Lat8]
new file mode 100644
index 000000000..c15713e82
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/5F[Lat8]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/62[Lat9] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/62[Lat9]
new file mode 100644
index 000000000..5bf449d58
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/62[Lat9]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/66[Lat10] b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/66[Lat10]
new file mode 100644
index 000000000..e8ba925d3
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/ISO2022/G96/66[Lat10]
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/KOI8-R b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/KOI8-R
new file mode 100644
index 000000000..8063cd4bc
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/KOI8-R
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1250 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1250
new file mode 100644
index 000000000..7a0d35ceb
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1250
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1251 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1251
new file mode 100644
index 000000000..3d6009cab
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1251
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1252 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1252
new file mode 100644
index 000000000..6d3bf293d
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1252
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1253 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1253
new file mode 100644
index 000000000..50a48be13
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1253
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1254 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1254
new file mode 100644
index 000000000..45ecfe907
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1254
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1256 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1256
new file mode 100644
index 000000000..7fc95a92f
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP1256
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP866 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP866
new file mode 100644
index 000000000..cd214d24b
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP866
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP874 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP874
new file mode 100644
index 000000000..26a6fc8c3
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP874
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP932 b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP932
new file mode 100644
index 000000000..2c0c111f9
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Encodings/Microsoft/CP932
Binary files differ
diff --git a/frontends/riscos/distribution/!Boot/Resources/!Unicode/Files/Aliases b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Files/Aliases
new file mode 100644
index 000000000..8978ede4c
--- /dev/null
+++ b/frontends/riscos/distribution/!Boot/Resources/!Unicode/Files/Aliases
@@ -0,0 +1,303 @@
+# > Unicode:Files.Aliases
+# Mapping of character set encoding names to their canonical form
+#
+# Lines starting with a '#' are comments, blank lines are ignored.
+#
+# Based on http://www.iana.org/assignments/character-sets and
+# http://www.iana.org/assignments/ianacharset-mib
+#
+# Canonical Form MIBenum Aliases...
+#
+US-ASCII 3 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII ISO646-US ANSI_X3.4-1968 us IBM367 cp367 csASCII
+ISO-10646-UTF-1 27 csISO10646UTF1
+ISO_646.basic:1983 28 ref csISO646basic1983
+INVARIANT 29 csINVARIANT
+ISO_646.irv:1983 30 iso-ir-2 irv csISO2IntlRefVersion
+BS_4730 20 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom
+NATS-SEFI 31 iso-ir-8-1 csNATSSEFI
+NATS-SEFI-ADD 32 iso-ir-8-2 csNATSSEFIADD
+NATS-DANO 33 iso-ir-9-1 csNATSDANO
+NATS-DANO-ADD 34 iso-ir-9-2 csNATSDANOADD
+SEN_850200_B 35 iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish
+SEN_850200_C 21 iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames
+KS_C_5601-1987 36 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987
+ISO-2022-KR 37 csISO2022KR
+EUC-KR 38 csEUCKR EUCKR
+ISO-2022-JP 39 csISO2022JP
+ISO-2022-JP-2 40 csISO2022JP2
+ISO-2022-CN 104
+ISO-2022-CN-EXT 105
+JIS_C6220-1969-jp 41 JIS_C6220-1969 iso-ir-13 katakana x0201-7 csISO13JISC6220jp
+JIS_C6220-1969-ro 42 iso-ir-14 jp ISO646-JP csISO14JISC6220ro
+IT 22 iso-ir-15 ISO646-IT csISO15Italian
+PT 43 iso-ir-16 ISO646-PT csISO16Portuguese
+ES 23 iso-ir-17 ISO646-ES csISO17Spanish
+greek7-old 44 iso-ir-18 csISO18Greek7Old
+latin-greek 45 iso-ir-19 csISO19LatinGreek
+DIN_66003 24 iso-ir-21 de ISO646-DE csISO21German
+NF_Z_62-010_(1973) 46 iso-ir-25 ISO646-FR1 csISO25French
+Latin-greek-1 47 iso-ir-27 csISO27LatinGreek1
+ISO_5427 48 iso-ir-37 csISO5427Cyrillic
+JIS_C6226-1978 49 iso-ir-42 csISO42JISC62261978
+BS_viewdata 50 iso-ir-47 csISO47BSViewdata
+INIS 51 iso-ir-49 csISO49INIS
+INIS-8 52 iso-ir-50 csISO50INIS8
+INIS-cyrillic 53 iso-ir-51 csISO51INISCyrillic
+ISO_5427:1981 54 iso-ir-54 ISO5427Cyrillic1981
+ISO_5428:1980 55 iso-ir-55 csISO5428Greek
+GB_1988-80 56 iso-ir-57 cn ISO646-CN csISO57GB1988
+GB_2312-80 57 iso-ir-58 chinese csISO58GB231280
+NS_4551-1 25 iso-ir-60 ISO646-NO no csISO60DanishNorwegian csISO60Norwegian1
+NS_4551-2 58 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2
+NF_Z_62-010 26 iso-ir-69 ISO646-FR fr csISO69French
+videotex-suppl 59 iso-ir-70 csISO70VideotexSupp1
+PT2 60 iso-ir-84 ISO646-PT2 csISO84Portuguese2
+ES2 61 iso-ir-85 ISO646-ES2 csISO85Spanish2
+MSZ_7795.3 62 iso-ir-86 ISO646-HU hu csISO86Hungarian
+JIS_C6226-1983 63 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208
+greek7 64 iso-ir-88 csISO88Greek7
+ASMO_449 65 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449
+iso-ir-90 66 csISO90
+JIS_C6229-1984-a 67 iso-ir-91 jp-ocr-a csISO91JISC62291984a
+JIS_C6229-1984-b 68 iso-ir-92 ISO646-JP-OCR-B jp-ocr-b csISO92JISC62991984b
+JIS_C6229-1984-b-add 69 iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd
+JIS_C6229-1984-hand 70 iso-ir-94 jp-ocr-hand csISO94JIS62291984hand
+JIS_C6229-1984-hand-add 71 iso-ir-95 jp-ocr-hand-add csISO95JIS62291984handadd
+JIS_C6229-1984-kana 72 iso-ir-96 csISO96JISC62291984kana
+ISO_2033-1983 73 iso-ir-98 e13b csISO2033
+ANSI_X3.110-1983 74 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS
+ISO-8859-1 4 iso-ir-100 ISO_8859-1 ISO_8859-1:1987 latin1 l1 IBM819 CP819 csISOLatin1 8859_1 ISO8859-1
+ISO-8859-2 5 iso-ir-101 ISO_8859-2 ISO_8859-2:1987 latin2 l2 csISOLatin2 8859_2 ISO8859-2
+T.61-7bit 75 iso-ir-102 csISO102T617bit
+T.61-8bit 76 T.61 iso-ir-103 csISO103T618bit
+ISO-8859-3 6 iso-ir-109 ISO_8859-3 ISO_8859-3:1988 latin3 l3 csISOLatin3 8859_3 ISO8859-3
+ISO-8859-4 7 iso-ir-110 ISO_8859-4 ISO_8859-4:1988 latin4 l4 csISOLatin4 8859_4 ISO8859-4
+ECMA-cyrillic 77 iso-ir-111 KOI8-E csISO111ECMACyrillic
+CSA_Z243.4-1985-1 78 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1
+CSA_Z243.4-1985-2 79 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2
+CSA_Z243.4-1985-gr 80 iso-ir-123 csISO123CSAZ24341985gr
+ISO-8859-6 9 iso-ir-127 ISO_8859-6 ISO_8859-6:1987 ECMA-114 ASMO-708 arabic csISOLatinArabic
+ISO-8859-6-E 81 csISO88596E ISO_8859-6-E
+ISO-8859-6-I 82 csISO88596I ISO_8859-6-I
+ISO-8859-7 10 iso-ir-126 ISO_8859-7 ISO_8859-7:1987 ELOT_928 ECMA-118 greek greek8 csISOLatinGreek 8859_7 ISO8859-7
+T.101-G2 83 iso-ir-128 csISO128T101G2
+ISO-8859-8 11 iso-ir-138 ISO_8859-8 ISO_8859-8:1988 hebrew csISOLatinHebrew 8859_8 ISO8859-8
+ISO-8859-8-E 84 csISO88598E ISO_8859-8-E
+ISO-8859-8-I 85 csISO88598I ISO_8859-8-I
+CSN_369103 86 iso-ir-139 csISO139CSN369103
+JUS_I.B1.002 87 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002
+ISO_6937-2-add 14 iso-ir-142 csISOTextComm
+IEC_P27-1 88 iso-ir-143 csISO143IECP271
+ISO-8859-5 8 iso-ir-144 ISO_8859-5 ISO_8859-5:1988 cyrillic csISOLatinCyrillic 8859_5 ISO8859-5
+JUS_I.B1.003-serb 89 iso-ir-146 serbian csISO146Serbian
+JUS_I.B1.003-mac 90 macedonian iso-ir-147 csISO147Macedonian
+ISO-8859-9 12 iso-ir-148 ISO_8859-9 ISO_8859-9:1989 latin5 l5 csISOLatin5 8859_9 ISO8859-9
+greek-ccitt 91 iso-ir-150 csISO150 csISO150GreekCCITT
+NC_NC00-10:81 92 cuba iso-ir-151 ISO646-CU csISO151Cuba
+ISO_6937-2-25 93 iso-ir-152 csISO6937Add
+GOST_19768-74 94 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874
+ISO_8859-supp 95 iso-ir-154 latin1-2-5 csISO8859Supp
+ISO_10367-box 96 iso-ir-155 csISO10367Box
+ISO-8859-10 13 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 8859_10 ISO8859-10
+latin-lap 97 lap iso-ir-158 csISO158Lap
+JIS_X0212-1990 98 x0212 iso-ir-159 csISO159JISX02121990
+DS_2089 99 DS2089 ISO646-DK dk csISO646Danish
+us-dk 100 csUSDK
+dk-us 101 csDKUS
+JIS_X0201 15 X0201 csHalfWidthKatakana
+KSC5636 102 ISO646-KR csKSC5636
+ISO-10646-UCS-2 1000 csUnicode UCS-2 UCS2
+ISO-10646-UCS-4 1001 csUCS4 UCS-4 UCS4
+DEC-MCS 2008 dec csDECMCS
+hp-roman8 2004 roman8 r8 csHPRoman8
+macintosh 2027 mac csMacintosh MACROMAN MAC-ROMAN X-MAC-ROMAN
+IBM037 2028 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037
+IBM038 2029 EBCDIC-INT cp038 csIBM038
+IBM273 2030 CP273 csIBM273
+IBM274 2031 EBCDIC-BE CP274 csIBM274
+IBM275 2032 EBCDIC-BR cp275 csIBM275
+IBM277 2033 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277
+IBM278 2034 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278
+IBM280 2035 CP280 ebcdic-cp-it csIBM280
+IBM281 2036 EBCDIC-JP-E cp281 csIBM281
+IBM284 2037 CP284 ebcdic-cp-es csIBM284
+IBM285 2038 CP285 ebcdic-cp-gb csIBM285
+IBM290 2039 cp290 EBCDIC-JP-kana csIBM290
+IBM297 2040 cp297 ebcdic-cp-fr csIBM297
+IBM420 2041 cp420 ebcdic-cp-ar1 csIBM420
+IBM423 2042 cp423 ebcdic-cp-gr csIBM423
+IBM424 2043 cp424 ebcdic-cp-he csIBM424
+IBM437 2011 cp437 437 csPC8CodePage437
+IBM500 2044 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500
+IBM775 2087 cp775 csPC775Baltic
+IBM850 2009 cp850 850 csPC850Multilingual
+IBM851 2045 cp851 851 csIBM851
+IBM852 2010 cp852 852 csPCp852
+IBM855 2046 cp855 855 csIBM855
+IBM857 2047 cp857 857 csIBM857
+IBM860 2048 cp860 860 csIBM860
+IBM861 2049 cp861 861 cp-is csIBM861
+IBM862 2013 cp862 862 csPC862LatinHebrew
+IBM863 2050 cp863 863 csIBM863
+IBM864 2051 cp864 csIBM864
+IBM865 2052 cp865 865 csIBM865
+IBM866 2086 cp866 866 csIBM866
+IBM868 2053 CP868 cp-ar csIBM868
+IBM869 2054 cp869 869 cp-gr csIBM869
+IBM870 2055 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870
+IBM871 2056 CP871 ebcdic-cp-is csIBM871
+IBM880 2057 cp880 EBCDIC-Cyrillic csIBM880
+IBM891 2058 cp891 csIBM891
+IBM903 2059 cp903 csIBM903
+IBM904 2060 cp904 904 csIBBM904
+IBM905 2061 CP905 ebcdic-cp-tr csIBM905
+IBM918 2062 CP918 ebcdic-cp-ar2 csIBM918
+IBM1026 2063 CP1026 csIBM1026
+EBCDIC-AT-DE 2064 csIBMEBCDICATDE
+EBCDIC-AT-DE-A 2065 csEBCDICATDEA
+EBCDIC-CA-FR 2066 csEBCDICCAFR
+EBCDIC-DK-NO 2067 csEBCDICDKNO
+EBCDIC-DK-NO-A 2068 csEBCDICDKNOA
+EBCDIC-FI-SE 2069 csEBCDICFISE
+EBCDIC-FI-SE-A 2070 csEBCDICFISEA
+EBCDIC-FR 2071 csEBCDICFR
+EBCDIC-IT 2072 csEBCDICIT
+EBCDIC-PT 2073 csEBCDICPT
+EBCDIC-ES 2074 csEBCDICES
+EBCDIC-ES-A 2075 csEBCDICESA
+EBCDIC-ES-S 2076 csEBCDICESS
+EBCDIC-UK 2077 csEBCDICUK
+EBCDIC-US 2078 csEBCDICUS
+UNKNOWN-8BIT 2079 csUnknown8BiT
+MNEMONIC 2080 csMnemonic
+MNEM 2081 csMnem
+VISCII 2082 csVISCII
+VIQR 2083 csVIQR
+KOI8-R 2084 csKOI8R
+KOI8-U 2088
+IBM00858 2089 CCSID00858 CP00858 PC-Multilingual-850+euro
+IBM00924 2090 CCSID00924 CP00924 ebcdic-Latin9--euro
+IBM01140 2091 CCSID01140 CP01140 ebcdic-us-37+euro
+IBM01141 2092 CCSID01141 CP01141 ebcdic-de-273+euro
+IBM01142 2093 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro
+IBM01143 2094 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro
+IBM01144 2095 CCSID01144 CP01144 ebcdic-it-280+euro
+IBM01145 2096 CCSID01145 CP01145 ebcdic-es-284+euro
+IBM01146 2097 CCSID01146 CP01146 ebcdic-gb-285+euro
+IBM01147 2098 CCSID01147 CP01147 ebcdic-fr-297+euro
+IBM01148 2099 CCSID01148 CP01148 ebcdic-international-500+euro
+IBM01149 2100 CCSID01149 CP01149 ebcdic-is-871+euro
+Big5-HKSCS 2101
+IBM1047 2102 IBM-1047
+PTCP154 2103 csPTCP154 PT154 CP154 Cyrillic-Asian
+Amiga-1251 2104 Ami1251 Amiga1251 Ami-1251
+KOI7-switched 2105
+UNICODE-1-1 1010 csUnicode11
+SCSU 1011
+UTF-7 1012
+UTF-16BE 1013
+UTF-16LE 1014
+UTF-16 1015
+CESU-8 1016 csCESU-8
+UTF-32 1017
+UTF-32BE 1018
+UTF-32LE 1019
+BOCU-1 1020 csBOCU-1
+UNICODE-1-1-UTF-7 103 csUnicode11UTF7
+UTF-8 106 UNICODE-1-1-UTF-8 UNICODE-2-0-UTF-8 utf8
+ISO-8859-13 109 8859_13 ISO8859-13
+ISO-8859-14 110 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic l8 8859_14 ISO8859-14
+ISO-8859-15 111 ISO_8859-15 Latin-9 8859_15 ISO8859-15
+ISO-8859-16 112 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10
+GBK 113 CP936 MS936 windows-936
+GB18030 114
+OSD_EBCDIC_DF04_15 115
+OSD_EBCDIC_DF03_IRV 116
+OSD_EBCDIC_DF04_1 117
+JIS_Encoding 16 csJISEncoding
+Shift_JIS 17 MS_Kanji csShiftJIS X-SJIS Shift-JIS
+EUC-JP 18 csEUCPkdFmtJapanese Extended_UNIX_Code_Packed_Format_for_Japanese EUCJP
+Extended_UNIX_Code_Fixed_Width_for_Japanese 19 csEUCFixWidJapanese
+ISO-10646-UCS-Basic 1002 csUnicodeASCII
+ISO-10646-Unicode-Latin1 1003 csUnicodeLatin1 ISO-10646
+ISO-Unicode-IBM-1261 1005 csUnicodeIBM1261
+ISO-Unicode-IBM-1268 1006 csUnicodeIBM1268
+ISO-Unicode-IBM-1276 1007 csUnicodeIBM1276
+ISO-Unicode-IBM-1264 1008 csUnicodeIBM1264
+ISO-Unicode-IBM-1265 1009 csUnicodeIBM1265
+ISO-8859-1-Windows-3.0-Latin-1 2000 csWindows30Latin1
+ISO-8859-1-Windows-3.1-Latin-1 2001 csWindows31Latin1
+ISO-8859-2-Windows-Latin-2 2002 csWindows31Latin2
+ISO-8859-9-Windows-Latin-5 2003 csWindows31Latin5
+Adobe-Standard-Encoding 2005 csAdobeStandardEncoding
+Ventura-US 2006 csVenturaUS
+Ventura-International 2007 csVenturaInternational
+PC8-Danish-Norwegian 2012 csPC8DanishNorwegian
+PC8-Turkish 2014 csPC8Turkish
+IBM-Symbols 2015 csIBMSymbols
+IBM-Thai 2016 csIBMThai
+HP-Legal 2017 csHPLegal
+HP-Pi-font 2018 csHPPiFont
+HP-Math8 2019 csHPMath8
+Adobe-Symbol-Encoding 2020 csHPPSMath
+HP-DeskTop 2021 csHPDesktop
+Ventura-Math 2022 csVenturaMath
+Microsoft-Publishing 2023 csMicrosoftPublishing
+Windows-31J 2024 csWindows31J
+GB2312 2025 csGB2312 EUC-CN EUCCN CN-GB
+Big5 2026 csBig5 BIG-FIVE BIG-5 CN-BIG5 BIG_FIVE x-x-big5
+windows-1250 2250 CP1250 MS-EE
+windows-1251 2251 CP1251 MS-CYRL
+windows-1252 2252 CP1252 MS-ANSI
+windows-1253 2253 CP1253 MS-GREEK
+windows-1254 2254 CP1254 MS-TURK
+windows-1255 2255
+windows-1256 2256 CP1256 MS-ARAB
+windows-1257 2257 CP1257 WINBALTRIM
+windows-1258 2258
+TIS-620 2259
+HZ-GB-2312 2085
+
+# Additional encodings not defined by IANA
+
+# Arbitrary allocations
+#CP737 3001
+#CP853 3002
+#CP856 3003
+CP874 3004 WINDOWS-874
+#CP922 3005
+#CP1046 3006
+#CP1124 3007
+#CP1125 3008 WINDOWS-1125
+#CP1129 3009
+#CP1133 3010 IBM-CP1133
+#CP1161 3011 IBM-1161 IBM1161 CSIBM1161
+#CP1162 3012 IBM-1162 IBM1162 CSIBM1162
+#CP1163 3013 IBM-1163 IBM1163 CSIBM1163
+#GEORGIAN-ACADEMY 3014
+#GEORGIAN-PS 3015
+#KOI8-RU 3016
+#KOI8-T 3017
+#MACARABIC 3018 X-MAC-ARABIC MAC-ARABIC
+#MACCROATIAN 3019 X-MAC-CROATIAN MAC-CROATIAN
+#MACGREEK 3020 X-MAC-GREEK MAC-GREEK
+#MACHEBREW 3021 X-MAC-HEBREW MAC-HEBREW
+#MACICELAND 3022 X-MAC-ICELAND MAC-ICELAND
+#MACROMANIA 3023 X-MAC-ROMANIA MAC-ROMANIA
+#MACTHAI 3024 X-MAC-THAI MAC-THAI
+#MACTURKISH 3025 X-MAC-TURKISH MAC-TURKISH
+#MULELAO-1 3026
+CP949 3027 WINDOWS-949
+
+# From Unicode Lib
+ISO-IR-182 4000
+ISO-IR-197 4002
+ISO-2022-JP-1 4008
+MACCYRILLIC 4009 X-MAC-CYRILLIC MAC-CYRILLIC
+MACUKRAINE 4010 X-MAC-UKRAINIAN MAC-UKRAINIAN
+MACCENTRALEUROPE 4011 X-MAC-CENTRALEURROMAN MAC-CENTRALEURROMAN
+JOHAB 4012
+ISO-8859-11 4014 iso-ir-166 ISO_8859-11 ISO8859-11 8859_11
+X-CURRENT 4999 X-SYSTEM
+X-ACORN-LATIN1 5001
+X-ACORN-FUZZY 5002
diff --git a/frontends/riscos/distribution/!System/310/Modules/CryptRand,ffa b/frontends/riscos/distribution/!System/310/Modules/CryptRand,ffa
new file mode 100644
index 000000000..f403843b3
--- /dev/null
+++ b/frontends/riscos/distribution/!System/310/Modules/CryptRand,ffa
Binary files differ
diff --git a/frontends/riscos/distribution/!System/310/Modules/Iconv,ffa b/frontends/riscos/distribution/!System/310/Modules/Iconv,ffa
new file mode 100644
index 000000000..8a9cc3adb
--- /dev/null
+++ b/frontends/riscos/distribution/!System/310/Modules/Iconv,ffa
Binary files differ
diff --git a/frontends/riscos/distribution/!System/310/Modules/Network/URI,ffa b/frontends/riscos/distribution/!System/310/Modules/Network/URI,ffa
new file mode 100644
index 000000000..431535e21
--- /dev/null
+++ b/frontends/riscos/distribution/!System/310/Modules/Network/URI,ffa
Binary files differ
diff --git a/frontends/riscos/distribution/!System/310/Modules/SharedULib,ffa b/frontends/riscos/distribution/!System/310/Modules/SharedULib,ffa
new file mode 100755
index 000000000..8dd0dd2c9
--- /dev/null
+++ b/frontends/riscos/distribution/!System/310/Modules/SharedULib,ffa
Binary files differ
diff --git a/frontends/riscos/distribution/!System/310/Modules/Tinct,ffa b/frontends/riscos/distribution/!System/310/Modules/Tinct,ffa
new file mode 100644
index 000000000..b8fda27b8
--- /dev/null
+++ b/frontends/riscos/distribution/!System/310/Modules/Tinct,ffa
Binary files differ
diff --git a/frontends/riscos/distribution/3rdParty/AcornURI/!ReadMe b/frontends/riscos/distribution/3rdParty/AcornURI/!ReadMe
new file mode 100644
index 000000000..4f4ca1e24
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/AcornURI/!ReadMe
@@ -0,0 +1,34 @@
+AcornURI 1.04
+-------------
+
+Hi. This is a complete reimplementation of Acorn's URI module such that it
+works on Iyonix. This allows simple URI / URL launching from applications.
+Merge this !System with your own, then (re)launch your favourite browser to
+ensure it's running.
+
+This has a few advantages over the official offering: it's smaller,
+compatible with more browsers and more tolerant of errors.
+
+This is released under the terms of the LGPL, which is included in this
+archive as the file Copying. Previous versions of this module were released
+under the GPL, and are still available from sudden.recoil.org.
+
+Source is available from the same place you downloaded this archive, ie
+<http://sudden.recoil.org/others/acornuri/acornuri104src.zip>
+
+
+Changelog
+---------
+
+v1.04 20-May-06 Relicensed under the LGPL (rather than GPL)
+
+v1.03 11-May-04 Changed the order of things to try, so it now
+ always prefers browsers which are already loaded
+
+v1.02 19-Feb-04 Fixed claiming of URIs where I'd misread the spec
+ Added automatic fall-back to the ANT protocol
+ Removed some service calls to improve reliability
+
+--
+Christian Ludlam
+chris@recoil.org \ No newline at end of file
diff --git a/frontends/riscos/distribution/3rdParty/AcornURI/Copying b/frontends/riscos/distribution/3rdParty/AcornURI/Copying
new file mode 100644
index 000000000..5ab7695ab
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/AcornURI/Copying
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/frontends/riscos/distribution/3rdParty/CryptRand/Copyright b/frontends/riscos/distribution/3rdParty/CryptRand/Copyright
new file mode 100644
index 000000000..abb4a9b80
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/CryptRand/Copyright
@@ -0,0 +1,46 @@
+CryptRandom
+
+Upstream sources were downloaded and built by
+the GCCSDK Autobuilder.
+
+For information on the autobuilder see the URL:
+
+http://www.riscos.info/index.php/GCCSDK#GCCSDK_Autobuilder
+
+The source used for this build can be found at
+
+http://www.riscos.info/packages/src/System
+
+Upstream source fetched by CVS with
+
+CVS root theom@chiark.greenend.org.uk:/u3/theom/cvs-pub
+Module cryptrandom
+Upstream source fetched using SVN from
+
+
+# For AOF builds needing another branch (if this is not defined AB_SVN is
+
+Copyright
+---------
+
+Copyright 2000-11 Theo Markettos <theo@markettos.org.uk>
+Portions copyright Simon Tatham, Gary S. Brown and Eric Young
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including without
+limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+SIMON TATHAM OR THEO MARKETTOS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/frontends/riscos/distribution/3rdParty/Iconv/ReadMe b/frontends/riscos/distribution/3rdParty/Iconv/ReadMe
new file mode 100644
index 000000000..907c2c7c8
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/Iconv/ReadMe
@@ -0,0 +1,45 @@
+What is Iconv?
+==============
+
+Iconv is a module which provides character set conversion akin to that provided
+by the C iconv() function.
+
+Iconv Installation instructions
+===============================
+
+To install the Iconv module, simply use the System merge utility provided by
+Configure to merge the !System directory provided with the one on your system.
+
+Use the Boot merge facility in Configure to merge the provided !Boot directory
+with the one on your system. If there is no !Boot merge facility provided on
+your system, simply drag the !Boot directory over your existing boot structure.
+
+Further documentation can be found in the "doc" directory.
+
+Note for developers:
+~~~~~~~~~~~~~~~~~~~~
+The "stubs" directory contains source for a set of C stubs.
+See the ReadMe file in that directory for further information.
+
+Licence
+=======
+
+Iconv is Copyright й 2004-13 J-M Bell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/frontends/riscos/distribution/3rdParty/Iconv/doc/API b/frontends/riscos/distribution/3rdParty/Iconv/doc/API
new file mode 100644
index 000000000..13fa22fce
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/Iconv/doc/API
@@ -0,0 +1,132 @@
+Iconv Module API
+================
+
+If using C, then you really should be using the libiconv stubs provided
+(or UnixLib, if appropriate). See the iconv.h header file for further
+documentation of these calls.
+
+Iconv_Open (&57540)
+-------------------
+
+ Create a conversion descriptor
+
+ On Entry: r0 -> string containing name of destination encoding (eg "UTF-8")
+ r1 -> string containing name of source encoding (eg "CP1252")
+
+ On Exit: r0 = conversion descriptor
+ All others preserved
+
+ Either encoding name may have a number of parameters appended to them.
+ Parameters are separated by a pair of forward-slashes ("//").
+ Currently defined parameters are:
+
+ Parameter: Destination: Source:
+
+ TRANSLIT Transliterate unrepresentable None
+ output.
+
+ The conversion descriptor is an opaque value. The user should not,
+ therefore, assume anything about its meaning, nor modify it in any way.
+ Doing so is guaranteed to result in undefined behaviour.
+
+
+Iconv_Iconv (&57541)
+--------------------
+
+ This SWI is deprecated and Iconv_Convert should be used instead.
+
+
+Iconv_Close (&57542)
+--------------------
+
+ Destroy a conversion descriptor
+
+ On Entry: r0 = conversion descriptor to destroy
+
+ On Exit: r0 = 0
+ All others preserved
+
+
+Iconv_Convert (&57543)
+---------------------
+
+ Convert a byte sequence to another encoding
+
+ On Entry: r0 = conversion descriptor returned by Iconv_Open
+ r1 -> input buffer (or NULL to reset encoding context)
+ r2 = length of buffer pointed to by r1
+ r3 -> output buffer
+ r4 = length of buffer pointed to by r3
+
+ On Exit: r0 = number of non-reversible conversions performed (always 0)
+ r1 -> updated input buffer pointer (after last input read)
+ r2 = number of bytes remaining in input buffer
+ r3 -> updated output buffer pointer (i.e. end of output)
+ r4 = number of free bytes in the output buffer
+ All others preserved
+
+ Note that all strings should be NUL-terminated so, if calling from BASIC,
+ some terminating character munging may be needed.
+
+
+Errors:
+
+Should an error occur, the SWI will return with V set and r0 -> error buffer.
+Note that only the error number will be filled in and may be one of:
+
+ ICONV_NOMEM (&81b900)
+ ICONV_INVAL (&81b901)
+ ICONV_2BIG (&81b902)
+ ICONV_ILSEQ (&81b903)
+
+These map directly to the corresponding C errno values.
+
+
+Iconv_CreateMenu (&57544)
+-------------------------
+
+ Create a menu data structure containing all available encodings.
+
+ On Entry: r0 = flags. All bits reserved, must be 0
+ r1 -> buffer, or 0 to read required length
+ r2 = length of buffer in r1
+ r3 -> currently selected encoding name, or 0 if none selected
+ r4 -> buffer for indirected data, or 0 to read length
+ r5 = length of buffer in r4
+
+ On Exit: r2 = required size of buffer in r1 if r1 = 0 on entry,
+ or length of data placed in buffer
+ r5 = required size of buffer in r4 if r4 = 0 on entry,
+ or length of data placed in buffer
+
+ Menu titles are direct form text buffers. Menu entries are indirect text.
+ Entry text is stored in the buffer pointed to by R4 on entry to this call.
+
+
+Iconv_DecodeMenu (&57545)
+-------------------------
+
+ Decode a selection in a menu generated by Iconv_CreateMenu.
+ Places the corresponding encoding name in the result buffer.
+
+ On Entry: r0 = flags. All bits reserved, must be 0
+ r1 -> menu definition
+ r2 -> menu selections, as per Wimp_Poll
+ r3 -> buffer for result or 0 to read required length
+ r4 = buffer length
+
+ On Exit: r4 = required size of buffer if r3 = 0 on entry,
+ or length of data placed in buffer (0 if no selected
+ encoding)
+
+ The menu selections block pointed to by r2 on entry should be based at
+ the root of the encodings menu structure (i.e. index 0 in the block
+ should correspond to the selection in the main encoding menu).
+
+ This call will update the selection status of the menu(s) appropriately.
+
+
+Example Code:
+=============
+
+Example code may be found in the IconvEg BASIC file.
diff --git a/frontends/riscos/distribution/3rdParty/Iconv/doc/ChangeLog b/frontends/riscos/distribution/3rdParty/Iconv/doc/ChangeLog
new file mode 100644
index 000000000..3a22a45fa
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/Iconv/doc/ChangeLog
@@ -0,0 +1,114 @@
+Iconv Changelog
+===============
+
+0.01 10-Sep-2004
+----------------
+
+ - Initial version - unreleased.
+
+0.02 27-Sep-2004
+----------------
+
+ - Use allocated SWI & error chunks.
+ - Fix issues in 8bit encoding handling.
+ - First public release.
+
+0.03 22-Jan-2005
+----------------
+
+ - Add Iconv_Convert SWI with improved interface.
+ - Deprecate Iconv_Iconv SWI.
+ - Add encoding name alias handling.
+ - Bundle !Unicode resource.
+
+0.04 08-Apr-2005
+----------------
+
+ - Improve parameter checking.
+ - Fix potential memory leaks.
+ - Add encoding menu creation and selection handling.
+
+0.05 27-Jun-2005
+----------------
+
+ - Improve encoding alias support, using external data file.
+ - Add StubsG build for A9home users.
+
+0.06 05-Nov-2005
+----------------
+
+ - Modified menu creation API to store indirected text in a
+ user-provided buffer. This change is backwards incompatible.
+
+0.07 11-Feb-2006
+----------------
+
+ - Corrected output values for E2BIG errors.
+ - Fixed input pointer update after successful conversion.
+
+0.08 11-Mar-2007
+----------------
+
+ - Tightened up parameter checking in various places.
+ - Improve aliases hash function.
+ - Make 8bit write function's return values match encoding_write
+ with encoding_WRITE_STRICT set.
+ - Fix bug in 8bit writing which resulted in the remaining buffer
+ size being reduced even if nothing was written.
+ - Improve support for endian-specific Unicode variants.
+ - Work around issue in UnicodeLib where remaining buffer size is
+ reduced if an attempt is made to write an unrepresentable character.
+ - Add rudimentary //TRANSLIT support - simply replaces with '?' for now.
+ - Make UnicodeLib handle raw ISO-8859-{1,2,9,10,15} and not attempt
+ ISO-6937-2-25 shift sequences.
+ - Remove StubsG build as A9home now has a C99 capable C library.
+ - Overhaul documentation.
+
+0.09 20-Nov-2008
+----------------
+
+ - Restructured source tree into cross-platform and RO-specific parts.
+ - New build system to go with this.
+ - Fixes for compiling with GCC4.
+ - Introduce *Iconv command which performs command line conversion.
+ - Fixes/improvements to the handlers for:
+ + US-ASCII
+ + UTF-8
+ + ISO-8859-7
+ + ISO-8859-8
+ + ISO-8859-11
+ + Windows-1256
+ + MacRoman
+ + JIS X 0208
+ + JIS X 0212
+ + KS X 1001
+ + EUC-JP
+ + Any ISO-2022 based charset that uses a 94x94 table in GR
+ + Johab
+ + ShiftJIS
+ - Add support for ISO-8859-16 (Latin 10)
+ - Significantly improve detection and reporting of error conditions
+
+0.10 29-Nov-2008
+----------------
+
+ - Fixes to the *Iconv command parameter parsing
+ - Ensure *Iconv outputs all converted data when the input is invalid
+ - Fix handling of illegal UTF-8 byte sequences
+ - Fix handling of incomplete multibyte input sequences.
+
+0.11 04-Jan-2011
+----------------
+
+ - Detect missing mapping file when using 8bit codecs. This prevents spurious
+ memory exhaustion errors.
+ - Toolchain used to build 0.10 turns out to have produced broken code.
+ - Minor additions to the charset alias mapping file.
+
+0.12 20-Jan-2013
+---------------
+
+ - Master alias mapping file now lives in ROOL repository.
+ - Correct handling of trailing valid shift sequences. Previously would
+ erroneously report EINVAL, instead of silently accepting them.
+ - Add proper transliteration behaviour when requested using //TRANSLIT.
diff --git a/frontends/riscos/distribution/3rdParty/Iconv/doc/Uni-iconv b/frontends/riscos/distribution/3rdParty/Iconv/doc/Uni-iconv
new file mode 100644
index 000000000..caea2d0f1
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/Iconv/doc/Uni-iconv
@@ -0,0 +1,204 @@
+Introduction:
+=============
+
+This file documents an approximate correlation between the data files
+provided in the !Unicode distribution and the encoding headers in GNU
+libiconv 1.9.1.
+
+Those with '?' in the iconv column either are not represented in iconv
+or I've missed the relevant header file ;)
+
+A number of encodings are present in the iconv distribution but not
+in !Unicode. These are documented at the end of this file.
+
+Changelog:
+==========
+
+v 0.01 (09-Sep-2004)
+~~~~~~~~~~~~~~~~~~~~
+Initial Incarnation
+
+v 0.02 (11-Sep-2004)
+~~~~~~~~~~~~~~~~~~~~
+Documented additional encodings supported by the Iconv module.
+Corrected list of !Unicode deficiencies.
+
+
+!Unicode->iconv:
+================
+
+Unicode: iconv: notes:
+
+Acorn.Latin1 riscos1.h
+
+Apple.CentEuro mac_centraleurope.h
+Apple.Cyrillic mac_cyrillic.h
+Apple.Roman mac_roman.h
+Apple.Ukrainian mac_ukraine.h
+
+BigFive big5.h
+
+ISO2022.C0.40[ISO646] ?
+
+ISO2022.C1.43[IS6429] ?
+
+ISO2022.G94.40[646old] iso646_cn.h
+ISO2022.G94.41[646-GB] ?
+ISO2022.G94.42[646IRV] ?
+ISO2022.G94.43[FinSwe] ?
+ISO2022.G94.47[646-SE] ?
+ISO2022.G94.48[646-SE] ?
+ISO2022.G94.49[JS201K] jisx0201.h top of JIS range
+ISO2022.G94.4A[JS201R] jisx0201.h iso646_jp.h bottom of JIS range
+ISO2022.G94.4B[646-DE] ?
+ISO2022.G94.4C[646-PT] ?
+ISO2022.G94.54[GB1988] ?
+ISO2022.G94.56[Teltxt] ?
+ISO2022.G94.59[646-IT] ?
+ISO2022.G94.5A[646-ES] ?
+ISO2022.G94.60[646-NO] ?
+ISO2022.G94.66[646-FR] ?
+ISO2022.G94.69[646-HU] ?
+ISO2022.G94.6B[Arabic] ?
+ISO2022.G94.6C[IS6397] ?
+ISO2022.G94.7A[SerbCr] ?
+
+ISO2022.G94x94.40[JS6226] ?
+ISO2022.G94x94.41[GB2312] gb2312.h
+ISO2022.G94x94.42[JIS208] jis0x208.h
+ISO2022.G94x94.43[KS1001] ksc5601.h
+ISO2022.G94x94.44[JIS212] jis0x212.h
+ISO2022.G94x94.47[CNS1] cns11643_1.h the tables differ
+ISO2022.G94x94.48[CNS2] cns11643_2.h
+ISO2022.G94x94.49[CNS3] cns11643_3.h
+ISO2022.G94x94.4A[CNS4] cns11643_4.h
+ISO2022.G94x94.4B[CNS5] cns11643_5.h
+ISO2022.G94x94.4C[CNS6] cns11643_6.h
+ISO2022.G94x94.4D[CNS7] cns11643_7.h
+
+ISO2022.G96.41[Lat1] iso8859_1.h
+ISO2022.G96.42[Lat2] iso8859_2.h
+ISO2022.G96.43[Lat3] iso8859_3.h
+ISO2022.G96.44[Lat4] iso8859_4.h
+ISO2022.G96.46[Greek] ?
+ISO2022.G96.47[Arabic] iso8859_6.h ISO-8859-6 ignored
+ISO2022.G96.48[Hebrew] ?
+ISO2022.G96.4C[Cyrill] ?
+ISO2022.G96.4D[Lat5] iso8859_5.h
+ISO2022.G96.50[LatSup] ?
+ISO2022.G96.52[IS6397] ?
+ISO2022.G96.54[Thai] tis620.h
+ISO2022.G96.56[Lat6] iso8859_6.h
+ISO2022.G96.58[L6Sami] ?
+ISO2022.G96.59[Lat7] iso8859_7.h
+ISO2022.G96.5C[Welsh] ?
+ISO2022.G96.5D[Sami] ?
+ISO2022.G96.5E[Hebrew] ?
+ISO2022.G96.5F[Lat8] iso8859_8.h
+ISO2022.G96.62[Lat9] iso8859_9.h
+
+KOI8-R koi8_r.h
+
+Microsoft.CP1250 cp1250.h
+Microsoft.CP1251 cp1251.h
+Microsoft.CP1252 cp1252.h
+Microsoft.CP1254 cp1254.h
+Microsoft.CP866 cp866.h
+Microsoft.CP932 cp932.h cp932ext.h
+
+iconv->!Unicode:
+================
+
+Iconv has the following encodings, which are not present in !Unicode.
+Providing a suitable data file for !Unicode is trivial. Whether UnicodeLib
+will then act upon the addition of these is unknown.
+This list is ordered as per libiconv's NOTES file.
+
+European & Semitic languages:
+
+ ISO-8859-16 (iso8859_16.h)
+ KOI8-{U,RU,T} (koi8_xx.h)
+ CP125{3,5,6,7} (cp125n.h)
+ CP850 (cp850.h)
+ CP862 (cp862.h)
+ Mac{Croatian,Romania,Greek,Turkish,Hebrew,Arabic} (mac_foo.h)
+
+Japanese:
+
+ None afaikt.
+
+Simplified Chinese:
+
+ GB18030 (gb18030.h, gb18030ext.h)
+ HZ-GB-2312 (hz.h)
+
+Traditional Chinese:
+
+ CP950 (cp950.h)
+ BIG5-HKSCS (big5hkscs.h)
+
+Korean:
+
+ CP949 (cp949.h)
+
+Armenian:
+
+ ARMSCII-8 (armscii_8.h)
+
+Georgian:
+
+ Georgian-Academy, Georgian-PS (georgian_academy.h, georgian_ps.h)
+
+Thai:
+
+ CP874 (cp874.h)
+ MacThai (mac_thai.h)
+
+Laotian:
+
+ MuleLao-1, CP1133 (mulelao.h, cp1133.h)
+
+Vietnamese:
+
+ VISCII, TCVN (viscii.h, tcvn.h)
+ CP1258 (cp1258.h)
+
+Unicode:
+
+ BE/LE variants of normal encodings. I assume UnicodeLib handles
+ these, but can't be sure.
+ C99 / JAVA - well, yes.
+
+
+Iconv Module:
+=============
+
+The iconv module is effectively a thin veneer around UnicodeLib. However,
+8bit encodings are implemented within the module rather than using the
+support in UnicodeLib. The rationale for this is simply that, although
+UnicodeLib will understand (and act upon - reportedly...) additions to
+the ISO2022 Unicode resource, other encodings are ignored. As the vast
+majority of outstanding encodings fall into this category, and the code
+is fairly simple, it made sense to implement it within the module.
+
+With use of the iconv module, the list of outstanding encodings is
+reduced to:
+
+ CP1255 (requires state-based transcoding)
+
+ GB18030 (not 8bit - reportedly a requirement of PRC)
+ HZ-GB-2312 (not 8bit - supported by IE4)
+
+ CP950 (not 8bit - a (MS) variant of Big5)
+ BIG5-HKSCS (not 8bit - again, a Big5 variant)
+
+ CP949 (not 8bit)
+
+ ARMSCII-8 (easily implemented, if required)
+
+ VISCII (easily implemented, if required)
+ CP1258, TCVN (requires state-based transcoding)
+
+Additionally, the rest of the CodePage encodings implemented in iconv
+but not listed above (due to omissions from the iconv documentation)
+are implemented by the iconv module.
diff --git a/frontends/riscos/distribution/3rdParty/SharedULib/Copyright b/frontends/riscos/distribution/3rdParty/SharedULib/Copyright
new file mode 100644
index 000000000..b6784ed06
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/SharedULib/Copyright
@@ -0,0 +1,761 @@
+UnixLib Copyright
+-----------------
+
+UnixLib is Copyright (c) 1995-1999 Simon Callan, Nick Burrett,
+Nicholas Clark and Peter Burwood.
+
+These contributors have expressed "no interest" in any further licensing or
+copyright in regards to UnixLib.
+
+Other sections are (c) 1999-2006 Nick Burrett, John Tytgat, Peter Naulls,
+Peter Teichmann, Alex Waugh, Christian Ludlam, Theo Markettos, Graham Shaw,
+James Bursa and John-Mark Bell.
+
+In January 2005, permission was obtained from all relevant contributors
+by Peter Naulls to license all past and present contributions to UnixLib
+(where possible) under the revised BSD license. The license is included
+in the next section and is applicable to all code in UnixLib that does not
+have an explicit license in its source.
+
+Prior to 4th January 2005 and after May 2001, UnixLib contained code licensed
+under the GNU General Public License, and versions of UnixLib produced
+between these dates are subject to the provisions of the GPL. We realised
+that this might cause potential problems with the wider use of UnixLib in
+RISC OS, and along with the desire to clarify the overall licensing status of
+UnixLib, GPL code was removed from UnixLib and the above permission from all
+copyright holders allowed UnixLib contributions to be relicensed as per the
+revised BSD license. The GPL is therefore not included in this notice
+as it is no longer relevant to UnixLib.
+
+
+Practical notes on using UnixLib in your own programs:
+
+This is a plain English version of guidelines for use of UnixLib in
+your programs. It does not override any of the licenses included
+below, but is intended to state instances when it may be used in
+free and non-free software. Where there is contradiction or
+ambiguity in this wording, please refer to the specifics of the licence
+in question. These recommendations are based upon our understading
+of the GPL/LGPL and BSD licenses and are subject to change should
+our understanding of the topics improve.
+
+ - Because UnixLib contains code that is subject to the Lesser GNU
+ Public License, the LGPL is the overriding consideration when
+ linking UnixLib to programs (unless the program itself is GPL).
+
+ - You are free to use sections of UnixLib in your own programs
+ subject to the conditions of that code. If the entirety of
+ that code is under a BSD license, then you can generally use
+ that code as you see fit, and there is no further obligation
+ from you as long as the copyright notice remains. If you
+ use LGPL code in your program, then your program must also be
+ distributed under the LGPL (or GPL).
+
+ - If you use UnixLib in its intended original form - that is as a
+ supporting library for ported programs to RISC OS - then your program
+ is subject to the LGPL; or the GPL if the program is covered by that.
+ Note that you must make the source and any modifications available to for
+ both if requested. This is of course equally true if you write an original
+ GPL program using UnixLib. In most cases, no additional action is
+ required of you, especially since source is usually readibly available.
+
+ - If you use UnixLib for a non-free program - whether that's commercial or
+ otherwise, then you should carefully read section 6 of the LGPL. This
+ applies, because at the present time, there is no practical method of
+ dynamic linking on RISC OS. At such time that UnixLib is available as a
+ shared library, then programs dynamically linking to it will no longer be
+ subject to the LPGL as applied to UnixLib.
+
+ - Section 6 means that in practice, you must supply, or offer to
+ supply either source or object code for your program.
+ This is mainly to allow rebuilding of the executable program
+ with later or modified versions of UnixLib. You must of course
+ supply (or better, contribute to the GCCSDK project) any
+ modifications you make to UnixLib upon request.
+
+
+Recommended reading:
+
+Frequently Asked Questions about the GNU GPL
+http://www.fsf.org/licenses/gpl-faq.html (has some sections on LGPL)
+
+About the justifications for using LGPL
+http://www.fsf.org/licenses/why-not-lgpl.html
+
+
+
+===========================================================================
+
+ Copyright (c) 1995-2005 UnixLib Developers
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===========================================================================
+
+Portions of UnixLib are copyright The Regents of the University of
+California.
+
+Portions of this library are copyright Sun Microsystems, Inc. The
+
+Portions of this library are derived from the GNU C Library and fall under
+the GNU Library General Public License.
+
+Portions of this library are copyright Henry Spencer.
+
+Portions of this library are copyright The Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.
+
+Portions of this library are copyright PostgreSQL Global Development Group.
+
+The licenses for the above are duplicated below.
+
+
+===========================================================================
+
+ Copyright (c) The Regents of the University of California.
+ All rights reserved.
+
+ This code is derived from software contributed to Berkeley by
+ Chris Torek.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by the University of
+ California, Berkeley and its contributors.
+ 4. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+===========================================================================
+
+ Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+ Developed at SunPro, a Sun Microsystems, Inc. business.
+ Permission to use, copy, modify, and distribute this
+ software is freely granted, provided that this notice
+ is preserved.
+
+===========================================================================
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+===========================================================================
+
+Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
+
+Development of this software was funded, in part, by Cray Research Inc.,
+UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
+Corporation, none of whom are responsible for the results. The author
+thanks all of them.
+
+Redistribution and use in source and binary forms -- with or without
+modification -- are permitted for any purpose, provided that
+redistributions in source form retain this entire copyright notice and
+indicate the origin and nature of any modifications.
+
+I'd appreciate being given credit for this package in the documentation
+of software which uses it, but that is not a requirement.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===========================================================================
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties. The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+
+===========================================================================
+
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this
+paragraph and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
diff --git a/frontends/riscos/distribution/3rdParty/Tinct/!Help b/frontends/riscos/distribution/3rdParty/Tinct/!Help
new file mode 100644
index 000000000..2e27e354f
--- /dev/null
+++ b/frontends/riscos/distribution/3rdParty/Tinct/!Help
@@ -0,0 +1,304 @@
+Tinct
+=====
+This module provides the necessary functionality to display alpha-blended
+sprites both scaled and otherwise. It also provides functions for dithering,
+error diffusion and performing bi-linear filtering to improve their appearance.
+
+
+Technical information
+ппппппппппппппппппппп
+To ensure future compatibility, this module does not patch the OS in any way
+and works in a totally legal way. It also does not write to itself in any
+way, so is suitable for running from ROM.
+ Redirection to sprites is supported, although due to the overheads involved
+with caching the colour translation tables it is not recommended that this is
+done frequently. There are some exceptions to this, however, as redirecting to
+a 16bpp or 32bpp mode sprite does not require any translation tables, and
+redirecting to a sprite that has the same mode and palette as the previous
+destination that Tinct was used for causes a minimum overhead as the
+translation tables are checked and cached values are used if possible.
+
+Format of a sprite with 8-bit alpha channel
+иииииииииииииииииииииииииииииииииииииииииии
+The sprite format used by Tinct differs from those used by RISC OS Select,
+and whilst facilities are supplied to convert sprites into the required format,
+no facilities are provided to manipulate them.
+ All sprites used by Tinct must be 32bpp, and cannot have a standard RISC OS
+mask specified. The basic format of the sprite is shown below, with the
+restrictions to the standard sprite format marked with an asterisk (*):
+
+ [+0] Offset to next sprite
+ [+4] Sprite name, up to 12 characters with trailing zeroes
+ [+16] Width in words - 1
+ [+20] Height in scan lines - 1
+ [+24] First bit used
+ [+28] Last bit used
+ [+32] Offset to sprite image
+ [+36] * Offset to sprite image (no mask allowed)
+ [+40] * Sprite type (must be 0x301680B5)
+
+Whereas for normal sprites the sprite image would be a series of colour words
+of the format RrGgBb00, alpha-blended sprites use the empty byte to specify
+the alpha value, ie RrGgBbAa.
+ The alpha values represent the blending level on a linear scale where 0x00
+represents that the source pixel is totally transparent and 0xff that it is
+totally opaque. It should be noted that as a standard 32bpp sprite (eg as
+created with !Paint) will have the alpha channel set to 0x00 by default no
+output will be visible when plotting as an alpha-blended sprite.
+
+Error handling
+ииииииииииииии
+If an incorrect sprite is attempted to be used, Tinct currently always returns
+error number 0x700 (SBadSpriteFile) rather than the specific cause of the
+problem (eg. BadDPI, BadMSFlags or BadPixelDepth) as OS_SpriteOp would do.
+There are several technical reasons for this behaviour, and future versions of
+Tinct may return more descriptive errors depending on the cause.
+
+
+SWIs provided
+ппппппппппппп
+Tinct provides four SWIs to plot sprites and one to convert sprites to their
+32bpp equivalent. All values supplied to Tinct must be in OS units, and the
+current OS clipping rectangle is used.
+ The sprite pointers provided are equivalent to calling OS_SpriteOp with
+bit 9 of the reason code set. To plot a sprite by name, the sprite should
+first be found by using OS_SpriteOp with reason code 0x18 and using the
+returned sprite address.
+
+Tinct_PlotAlpha (0x57240)
+иииииииииииииииииииииииии
+Plots an alpha-blended sprite at the specified coordinates.
+
+-> R2 Sprite pointer
+ R3 X coordinate
+ R4 Y coordinate
+ R7 Flag word
+
+
+Tinct_PlotScaledAlpha (0x57241)
+иииииииииииииииииииииииииииииии
+Plots a scaled alpha-blended sprite at the specified coordinates.
+
+-> R2 Sprite pointer
+ R3 X coordinate
+ R4 Y coordinate
+ R5 Scaled sprite width
+ R6 Scaled sprite height
+ R7 Flag word
+
+
+Tinct_Plot (0x57242)
+ииииииииииииииииииии
+Plots a sprite at the specified coordinates with a constant 0xff value for
+the alpha channel, ie without a mask.
+
+-> R2 Sprite pointer
+ R3 X coordinate
+ R4 Y coordinate
+ R7 Flag word
+
+
+Tinct_PlotScaled (0x57243)
+ииииииииииииииииииииииииии
+Plots a scaled sprite at the specified coordinates with a constant 0xff value
+for the alpha channel, ie without a mask.
+
+-> R2 Sprite pointer
+ R3 X coordinate
+ R4 Y coordinate
+ R5 Scaled sprite width
+ R6 Scaled sprite height
+ R7 Flag word
+
+
+Tinct_ConvertSprite (0x57244)
+иииииииииииииииииииииииииииии
+Converts a paletted sprite into its 32bpp equivalent. Sufficient memory must
+have previously been allocated for the sprite (44 + width * height * 4).
+ As sprites with 16bpp or 32bpp do not have palettes, conversion cannot be
+performed on these variants. All sprites must be supplied with a full palette,
+eg 8bpp must have 256 palette entries.
+
+-> R2 Source sprite pointer
+ R3 Destination sprite pointer
+
+
+Tinct_AvailableFeatures (0x57245)
+иииииииииииииииииииииииииииииииии
+Returns the features available to the caller by specifying bits in the flag
+word. The features available are unique for each mode, although the current
+version of Tinct supports the same subset of features for all modes.
+
+-> R0 Feature to test for, or 0 for all features
+<- R0 Features available
+
+
+Tinct_Compress (0x57246)
+ииииииииииииииииииииииии
+Compresses an image using a fast algorithm. Sufficient memory must have been
+previously allocated for the maximum possible compressed size. This value is
+equal to 28 + (width * height * 4) * 33 / 32.
+
+-> R0 Source sprite pointer
+ R2 Output data buffer
+ R3 Output bytes available
+ R7 Flag word
+<- R0 Size of compressed data
+
+
+Tinct_Decompress (0x57247)
+ииииииииииииииииииииииииии
+Decompresses an image previously compressed. Sufficient memory must have been
+previously allocated for the decompressed data (44 + width * height * 4) where
+width and height are available at +0 and +4 of the compressed data respectively.
+
+-> R0 Input data buffer
+ R2 Output data buffer
+ R7 Flag word (currently 0)
+<- R0 Size of decompressed data
+
+
+Flag word (plotting)
+пппппппппппппппппппп
+All the SWIs provided by Tinct for plotting use a common flag word to
+describe the manner in which the plot is performed. Each bit controls a
+particular characteristic of the plotting:
+
+ 0 Forcibly read the screen base (only use if hardware scrolling)
+ 1 Use bi-linear filtering when scaling sprites
+ 2 Dither colours in 16bpp and below
+ 3 Perform error diffusion if bit 2 clear, invert dither pattern if set
+ 4 Horizontally fill the current graphics window with the sprite
+ 5 Vertically fill the current graphics window with the sprite
+ 6 Forcibly read the palette (only use if changing palette outside of
+ the WIMP)
+ 7 Use OS_SpriteOp to perform final plotting (see note)
+ 8+ Reserved (must be 0) if bit 7 is clear, background colour to
+ blend the alpha channel to otherwise
+
+If a bit is set in the flag word that cannot be honoured by the current
+version of Tinct then it is ignored. Tinct_AvailableFeatures can be used
+to test in advance what flags will be honoured.
+
+Bi-linear filtering
+иииииииииииииииииии
+Although bi-linear filtering is only relevant during scaled plotting, this
+situation occurs when the EigFactors of the mode are not equal. As such, an
+application should always set their preferred flags to ensure consistency. The
+case of XEig * 2 = YEig (rectangular pixel modes) for even height sprites is a
+special case and has optimised code implemented.
+ There is an upper limit to the size of sprite that can be bi-linear filtered.
+The checks that are currently made are:
+
+ scaled_width / sprite_width < 256
+ scaled_height / sprite_height < 256
+ scaled_width * max(sprite_height, scaled_height) < 32,768
+
+ It should be noted that as bi-linear filtering is performed as a pre-filter,
+it carries a sizable overhead. However, as all scaling calculations are
+performed during this filter, tiled plotting (bits 4 and 5) are affected by
+a smaller margin (in certain cases a speed gain can be achieved).
+ As bi-linear filtering is performed using a pre-filter, it can be used in
+association with OS_SpriteOp rendering.
+
+Error diffusion and dithering
+иииииииииииииииииииииииииииии
+If both error diffusion and dithering are enabled then the image is plotted
+using only dithering, but with the dither pattern inverted. This enables an
+application to provide the user with what appears to be a higher quality image
+by redrawing every frame with the flag toggled.
+ There is a significant speed difference between dithering and error diffusion,
+and Tinct does not support error diffusion in all colour depths. If error
+diffusion is requested, but cannot be performed by Tinct then dithering with
+an inverted pattern is used (as if bits 2 and 3 were set).
+ There is an upper limit to the size of sprite that Tinct can perform error
+diffusion on. This is currently set to a display width of 2047 pixels wide with
+an unlimited height. Any attempt to use a higher resolution will result in
+dithered rendering with an inverted pattern (ie bits 2 and 3 set).
+ As error diffusion and dithering are implemented during the plot cycle, it is
+not possible to use them in association with OS_SpriteOp rendering. However,
+the bits should be set as future versions of Tinct may respect them for users
+of RISC OS 3.1 where true colour sprites are not supported.
+
+Sprite filling
+ииииииииииииии
+If filling is specified, then the supplied co-ordinate is the offset of the
+pattern relative to (0, 0) used for the fill. For example, a 64x64 sprite that
+is plotted with bits 4 and 5 set and a position of (32, 16) would fill the
+current graphics window with multiple copies of the image stating with the
+first image plotted at (-32, -48).
+ The caller should not concern itself with the size of the image being tiled
+as small images are internally optimised where possible to maximise the
+plotting speed.
+
+Rendering using OS_SpriteOp
+иииииииииииииииииииииииииии
+It can be useful to use Tinct to perform the rendering to using OS_SpriteOp.
+There are two general situations where this may be useful:
+
+ 1) To output to a printer driver
+ 2) To allow hardware acceleraton (such as a ViewFinder card)
+
+By using Tinct rather than a direct OS_SpriteOp call, it allows the caller to
+retain certain features Tinct provides (such as sprite filling and a limited
+version of the standard alpha blending) and allows the caller to have a common
+plotting interface.
+ When using this feature for alpha-blended sprites, the background colour
+specified in the top 24-bits of the flag word is used for blending with any
+pixels that are not transparent. This requires that Tinct requires a second
+copy of the sprite in memory to modify which may present a significant overhead
+in some situations. Plotting opaquely does not have any such overheads.
+ Using OS_SpriteOp rendering does not currently work on RISC OS 3.1 or earlier
+due to the lack of support for true colour sprites. Future versions of Tinct
+may remove this restriction.
+
+
+Flag word (compression)
+ппппппппппппппппппппппп
+The flag word used by Tinct_Compress can be used to improve the compression
+ratio by performing pre-filtering on the data. The flags below relate only to
+compression and should not be passed to Tinct_Decompress.
+
+ 0 Image is opaque, remove the alpha channel prior to compression
+
+All unspecified bits are reserved for future expansion and as such should be
+set to 0.
+
+Compressed data format
+ииииииииииииииииииииии
+Certain aspects of the compressed data format are guaranteed to remain constant,
+so may be used by applications.
+
+ +0 Sprite width
+ +4 Sprite height
+ +8 Sprite name (12 chars)
+ +20 Compression flags
+ +24 Number of bytes of data following
+
+The method of compression is not guaranteed to remain constant over future
+revisions of Tinct, but subsequent versions will decompress data compressed
+with previous versions.
+
+
+Contact details
+ппппппппппппппп
+If you would like to report a problem relating to Tinct, provide feedback, or
+request a licence for a commercial product, please use the details below:
+
+Address: 5 Queens Close, East Markham, Newark, Nottinghamshire, NG22 0QY. UK
+E-mail: info@tinct.net
+Website: www.tinct.net
+
+
+Copyright and licence details
+ппппппппппппппппппппппппппппп
+Tinct is й copyright Richard Wilson, 2004.
+
+Distribution and usage
+ииииииииииииииииииииии
+Unrestricted use of Tinct is hereby granted for any non-commercial product. Any
+use as part of a commercial product requires written consent from the author.
+No charge may be made relating to the distribution of this software, and this
+copyright information should be included in all copies of the software.
+ Modified versions of this program may not be distributed without the authors
+consent, nor may modified versions of the source code or relating files. \ No newline at end of file
diff --git a/frontends/riscos/distribution/LeesMij b/frontends/riscos/distribution/LeesMij
new file mode 100644
index 000000000..a0d3ff41f
--- /dev/null
+++ b/frontends/riscos/distribution/LeesMij
@@ -0,0 +1,73 @@
+NetSurf
+=======
+
+Dit is een ontwikkelversie van NetSurf, een webbrowser met open
+broncode.
+
+De nieuwste versie van NetSurf is verkrijgbaar via:
+
+ http://www.netsurf-browser.org/
+
+
+Installatie
+-----------
+
+De installatie gaat in drie stappen:
+
+ 1. Gebruik de samenvoegfaciliteit van !Boot (te openen via de
+ besturingssysteeminstellingen -> !Boot) om de meegeleverde
+ !Boot-map samen te voegen met die van het systeem.
+
+ Als het besturingssysteem geen !Boot-samenvoegfaciliteit
+ ondersteund, sleep dan de meegeleverde !Boot-map in de map
+ waarin de bestaande !Boot-structuur staat.
+
+ 2. Gebruik de samenvoegfaciliteit van !System (te openen via de
+ besturingssysteeminstellingen -> !System) om de meegeleverde
+ !System-map samen te voegen met die van het systeem.
+
+ 3. Sleep de !NetSurf-programmamap naar de gewenste map op de
+ harde schijf.
+
+Dubbelklik op het programma !NetSurf in de gekozen locatie om de
+NetSurf-browser te starten.
+
+
+Opmerking NetSurf vereist de WindowManager-module 3.80 of een
+ recentere versie. Deze is standaard aanwezig in RISC OS 4
+ of een recentere versie. Voor RISC OS 3-gebruikers zijn
+ er twee mogelijkheden om NetSurf te kunnen gebruiken:
+
+ - De 'Universal !Boot Sequence' van Acorn:
+ http://www.riscos.com/ftp_space/generic/uniboot/
+ - HardDisc4-schijfstructuur van RISC OS Open:
+ https://www.riscosopen.org/content/downloads/common/
+
+
+Opmerking RISC OS 3.1 of oudere versies worden niet ondersteund.
+
+
+Licenties
+---------
+
+NetSurf wordt geleverd onder de GPL, evenals verschillende andere
+licenties voor de verschillende componenten die het programma
+gebruikt. Bezoek in de NetSurf-browser het URL-adres 'about:licence'
+voor meer informatie.
+
+
+De meegeleverde !Boot- en !System-mappen bevatten items die door
+derden zijn geproduceerd. De bijbehorende licenties zijn meegeleverd
+in de map '3rdParty'.
+
+AcornURI
+ http://sudden.recoil.org/others/
+
+Iconv
+ http://www.netsurf-browser.org/iconv/
+
+SharedUnixLibrary
+ http://www.riscos.info/downloads/gccsdk/sharedunixlib/system.zip
+
+Tinct
+ http://www.tinct.net/tinct.asp
diff --git a/frontends/riscos/distribution/ReadMe b/frontends/riscos/distribution/ReadMe
new file mode 100644
index 000000000..eec39d6ab
--- /dev/null
+++ b/frontends/riscos/distribution/ReadMe
@@ -0,0 +1,61 @@
+NetSurf
+=======
+
+This is a development build of NetSurf, an open source web browser.
+
+The latest version of NetSurf is available from:
+
+ http://www.netsurf-browser.org/
+
+
+Installation
+------------
+
+Installation is a three step process:
+
+ 1. Use the Boot Merge facility provided by Configure to merge
+ the supplied !Boot directory with the one on your system.
+
+ If there is no !Boot merge facility on your system, simply
+ drag the supplied !Boot over your existing boot structure.
+
+ 2. Use the System Merge facility provided by Configure to merge
+ the supplied !System directory with the one on your system.
+
+ 3. Drag the !NetSurf application directory to a place on your
+ hard disc.
+
+Double click on !NetSurf in your chosen location to launch NetSurf.
+
+
+Note NetSurf requires WindowManager 3.80 or later. This comes
+ with RISC OS 4 and above. RISC OS 3 users should install
+ the Universal Boot Sequence from:
+ http://acorn.riscos.com/riscos/releases/UniBoot/
+
+Note RISC OS 3.1 and earlier are not supported.
+
+
+Licences
+--------
+
+NetSurf is provided under the GPL, as well as several other licences
+for different components it uses. Visit NetSurf's about:licence URL
+for details.
+
+
+The !Boot and !System directories contain items provided produced
+by third parties. Their licences are provided in the 3rd Party
+directory.
+
+AcornURI
+ http://sudden.recoil.org/others/
+
+Iconv
+ http://www.netsurf-browser.org/iconv/
+
+SharedUnixLibrary
+ http://www.riscos.info/downloads/gccsdk/sharedunixlib/system.zip
+
+Tinct
+ http://www.tinct.net/tinct.asp
diff --git a/frontends/riscos/download.c b/frontends/riscos/download.c
new file mode 100644
index 000000000..cddb449de
--- /dev/null
+++ b/frontends/riscos/download.c
@@ -0,0 +1,1629 @@
+/*
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2003 Rob Jackson <jacko@xms.ms>
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * RISC OS download windows implementation.
+ *
+ * This file implements the interface given by desktop/gui_download.h
+ * for download windows. Each download window has an associated
+ * fetch. Downloads start by writing received data to a temporary
+ * file. At some point the user chooses a destination (by drag &
+ * drop), and the temporary file is then moved to the destination and
+ * the download continues until complete.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <curl/curl.h>
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "oslib/mimemap.h"
+#include "oslib/osargs.h"
+#include "oslib/osfile.h"
+#include "oslib/osfind.h"
+#include "oslib/osfscontrol.h"
+#include "oslib/osgbpb.h"
+#include "oslib/wimp.h"
+#include "oslib/wimpspriteop.h"
+
+#include "utils/sys_time.h"
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/nsurl.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+#include "utils/string.h"
+#include "utils/corestrings.h"
+#include "desktop/gui_download.h"
+#include "desktop/download.h"
+
+#include "riscos/gui.h"
+#include "riscos/dialog.h"
+#include "riscos/mouse.h"
+#include "riscos/save.h"
+#include "riscos/query.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/ucstables.h"
+#include "riscos/filetype.h"
+
+#define ICON_DOWNLOAD_ICON 0
+#define ICON_DOWNLOAD_URL 1
+#define ICON_DOWNLOAD_PATH 2
+#define ICON_DOWNLOAD_DESTINATION 3
+#define ICON_DOWNLOAD_PROGRESS 5
+#define ICON_DOWNLOAD_STATUS 6
+
+#define RO_DOWNLOAD_MAX_PATH_LEN 255
+
+typedef enum
+{
+ QueryRsn_Quit,
+ QueryRsn_Abort,
+ QueryRsn_Overwrite
+} query_reason;
+
+
+/** Data for a download window. */
+struct gui_download_window {
+ /** Associated context, or 0 if the fetch has completed or aborted. */
+ download_context *ctx;
+ unsigned int received; /**< Amount of data received so far. */
+ unsigned int total_size; /**< Size of resource, or 0 if unknown. */
+
+ wimp_w window; /**< RISC OS window handle. */
+ bits file_type; /**< RISC OS file type. */
+
+ char url[256]; /**< Buffer for URL icon. */
+ char sprite_name[20]; /**< Buffer for sprite icon. */
+ char path[RO_DOWNLOAD_MAX_PATH_LEN]; /**< Buffer for pathname icon. */
+ char status[256]; /**< Buffer for status icon. */
+
+ /** User has chosen the destination, and it is being written. */
+ bool saved;
+ bool close_confirmed;
+ bool error; /**< Error occurred, aborted. */
+
+ /** RISC OS file handle, of temporary file when !saved, and of
+ * destination when saved. */
+ os_fw file;
+
+ query_id query;
+ query_reason query_rsn;
+
+ struct timeval start_time; /**< Time download started. */
+ struct timeval last_time; /**< Time status was last updated. */
+ unsigned int last_received; /**< Value of received at last_time. */
+ float average_rate; /**< Moving average download rate. */
+ unsigned int average_points; /**< Number of points in the average. */
+
+ bool send_dataload; /**< Should send DataLoad message when finished */
+ wimp_message save_message; /**< Copy of wimp DataSaveAck message */
+
+ struct gui_download_window *prev; /**< Previous in linked list. */
+ struct gui_download_window *next; /**< Next in linked list. */
+};
+
+
+/** List of all download windows. */
+static struct gui_download_window *download_window_list = 0;
+/** Download window with current save operation. */
+static struct gui_download_window *download_window_current = 0;
+
+/** Template for a download window. */
+static wimp_window *download_template;
+
+/** Width of progress bar at 100%. */
+static int download_progress_width;
+/** Coordinates of progress bar. */
+static int download_progress_x0;
+static int download_progress_y0;
+static int download_progress_y1;
+
+/** Current download directory. */
+static char *download_dir = NULL;
+static size_t download_dir_len;
+
+static void ro_gui_download_drag_end(wimp_dragged *drag, void *data);
+static const char *ro_gui_download_temp_name(struct gui_download_window *dw);
+static void ro_gui_download_update_status(struct gui_download_window *dw);
+static void ro_gui_download_update_status_wrapper(void *p);
+static void ro_gui_download_window_hide_caret(struct gui_download_window *dw);
+static char *ro_gui_download_canonicalise(const char *path);
+static bool ro_gui_download_check_space(struct gui_download_window *dw,
+ const char *dest_file, const char *orig_file);
+static os_error *ro_gui_download_move(struct gui_download_window *dw,
+ const char *dest_file, const char *src_file);
+static void ro_gui_download_remember_dir(const char *path);
+static bool ro_gui_download_save(struct gui_download_window *dw,
+ const char *file_name, bool force_overwrite);
+static void ro_gui_download_send_dataload(struct gui_download_window *dw);
+static void ro_gui_download_window_destroy_wrapper(void *p);
+static bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit);
+static void ro_gui_download_close_confirmed(query_id, enum query_response res, void *p);
+static void ro_gui_download_close_cancelled(query_id, enum query_response res, void *p);
+static void ro_gui_download_overwrite_confirmed(query_id, enum query_response res, void *p);
+static void ro_gui_download_overwrite_cancelled(query_id, enum query_response res, void *p);
+
+static bool ro_gui_download_click(wimp_pointer *pointer);
+static bool ro_gui_download_keypress(wimp_key *key);
+static void ro_gui_download_close(wimp_w w);
+
+static const query_callback close_funcs =
+{
+ ro_gui_download_close_confirmed,
+ ro_gui_download_close_cancelled
+};
+
+static const query_callback overwrite_funcs =
+{
+ ro_gui_download_overwrite_confirmed,
+ ro_gui_download_overwrite_cancelled
+};
+
+
+/**
+ * Load the download window template.
+ */
+
+void ro_gui_download_init(void)
+{
+ download_template = ro_gui_dialog_load_template("download");
+ download_progress_width =
+ download_template->icons[ICON_DOWNLOAD_STATUS].extent.x1 -
+ download_template->icons[ICON_DOWNLOAD_STATUS].extent.x0;
+ download_progress_x0 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.x0;
+ download_progress_y0 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.y0;
+ download_progress_y1 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.y1;
+}
+
+
+/**
+ * Returns the pathname of a temporary file for this download.
+ *
+ * \param dw download window
+ * \return ptr to pathname
+ */
+
+const char *ro_gui_download_temp_name(struct gui_download_window *dw)
+{
+ static char temp_name[40];
+ snprintf(temp_name, sizeof temp_name, "<Wimp$ScrapDir>.ns%x",
+ (unsigned int) dw);
+ return temp_name;
+}
+
+/**
+ * Try and find the correct RISC OS filetype from a download context.
+ */
+static nserror download_ro_filetype(download_context *ctx, bits *ftype_out)
+{
+ nsurl *url = download_context_get_url(ctx);
+ bits ftype = 0;
+ lwc_string *scheme;
+
+ /* If the file is local try and read its filetype */
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+ if (scheme != NULL) {
+ bool filescheme;
+ if (lwc_string_isequal(scheme,
+ corestring_lwc_file,
+ &filescheme) != lwc_error_ok) {
+ filescheme = false;
+ }
+
+ if (filescheme) {
+ lwc_string *path = nsurl_get_component(url, NSURL_PATH);
+ if (path != NULL && lwc_string_length(path) != 0) {
+ char *raw_path;
+ raw_path = curl_unescape(lwc_string_data(path),
+ lwc_string_length(path));
+ if (raw_path != NULL) {
+ ftype = ro_filetype_from_unix_path(raw_path);
+ curl_free(raw_path);
+ }
+ }
+ }
+ }
+
+ /* If we still don't have a filetype (i.e. failed reading local
+ * one or fetching a remote object), then use the MIME type.
+ */
+ if (ftype == 0) {
+ /* convert MIME type to RISC OS file type */
+ os_error *error;
+ const char *mime_type;
+
+ mime_type = download_context_get_mime_type(ctx);
+ error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype);
+ if (error) {
+ LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ ftype = 0xffd;
+ }
+ }
+
+ *ftype_out = ftype;
+ return NSERROR_OK;
+}
+
+/**
+ * Create and open a download progress window.
+ *
+ * \param ctx Download context
+ * \param gui The RISCOS gui window to download for.
+ * \return A new gui_download_window structure, or NULL on error and error
+ * reported
+ */
+
+static struct gui_download_window *
+gui_download_window_create(download_context *ctx, struct gui_window *gui)
+{
+ nsurl *url = download_context_get_url(ctx);
+ const char *temp_name;
+ char *filename = NULL;
+ struct gui_download_window *dw;
+ bool space_warning = false;
+ os_error *error;
+ char *local_path;
+ nserror err;
+ size_t i, last_dot;
+
+ dw = malloc(sizeof *dw);
+ if (!dw) {
+ ro_warn_user("NoMemory", 0);
+ return 0;
+ }
+
+ dw->ctx = ctx;
+ dw->saved = false;
+ dw->close_confirmed = false;
+ dw->error = false;
+ dw->query = QUERY_INVALID;
+ dw->received = 0;
+ dw->total_size = download_context_get_total_length(ctx);
+
+ /** @todo change this to take a reference to the nsurl and use
+ * that value directly rather than using a fixed buffer.
+ */
+ strncpy(dw->url, nsurl_access(url), sizeof dw->url);
+ dw->url[sizeof dw->url - 1] = 0;
+
+ dw->status[0] = 0;
+ gettimeofday(&dw->start_time, 0);
+ dw->last_time = dw->start_time;
+ dw->last_received = 0;
+ dw->file_type = 0;
+ dw->average_rate = 0;
+ dw->average_points = 0;
+
+ /* get filetype */
+ err = download_ro_filetype(ctx, &dw->file_type);
+ if (err != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(err), 0);
+ free(dw);
+ return 0;
+ }
+
+ /* open temporary output file */
+ temp_name = ro_gui_download_temp_name(dw);
+ if (!ro_gui_download_check_space(dw, temp_name, NULL)) {
+ /* issue a warning but continue with the download because the
+ user can save it to another medium whilst it's downloading */
+ space_warning = true;
+ }
+ error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
+ temp_name, 0, &dw->file);
+ if (error) {
+ LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ free(dw);
+ return 0;
+ }
+
+ /* fill in download window icons */
+ download_template->icons[ICON_DOWNLOAD_URL].data.indirected_text.text =
+ dw->url;
+ download_template->icons[ICON_DOWNLOAD_URL].data.indirected_text.size =
+ sizeof dw->url;
+
+ download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.
+ text = dw->status;
+ download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.
+ size = sizeof dw->status;
+
+ sprintf(dw->sprite_name, "file_%.3x", dw->file_type);
+ if (!ro_gui_wimp_sprite_exists(dw->sprite_name))
+ strcpy(dw->sprite_name, "file_xxx");
+ download_template->icons[ICON_DOWNLOAD_ICON].data.indirected_sprite.id =
+ (osspriteop_id) dw->sprite_name;
+
+ /* Get a suitable path- and leafname for the download. */
+ temp_name = download_context_get_filename(dw->ctx);
+
+ if (temp_name == NULL)
+ temp_name = messages_get("SaveObject");
+
+ if (temp_name != NULL)
+ filename = strdup(temp_name);
+
+ if (filename == NULL) {
+ LOG("Failed to establish download filename.");
+ ro_warn_user("SaveError", error->errmess);
+ free(dw);
+ return 0;
+ }
+
+ for (i = 0, last_dot = (size_t) -1; filename[i] != '\0'; i++) {
+ const char c = filename[i];
+
+ if (c == '.') {
+ last_dot = i;
+ filename[i] = '/';
+ } else if (c <= ' ' || strchr(":*#$&@^%\\", c) != NULL)
+ filename[i] = '_';
+ }
+
+ if (nsoption_bool(strip_extensions) && last_dot != (size_t) -1)
+ filename[last_dot] = '\0';
+
+ if (download_dir != NULL && strlen(download_dir) > 0)
+ snprintf(dw->path, RO_DOWNLOAD_MAX_PATH_LEN, "%s.%s",
+ download_dir, filename);
+ else
+ snprintf(dw->path, RO_DOWNLOAD_MAX_PATH_LEN, "%s",
+ filename);
+
+ free(filename);
+
+ err = utf8_to_local_encoding(dw->path, 0, &local_path);
+ if (err != NSERROR_OK) {
+ /* badenc should never happen */
+ assert(err !=NSERROR_BAD_ENCODING);
+ LOG("utf8_to_local_encoding failed");
+ ro_warn_user("NoMemory", 0);
+ free(dw);
+ return 0;
+ }
+ else {
+ strncpy(dw->path, local_path, sizeof dw->path);
+ free(local_path);
+ }
+
+ download_template->icons[ICON_DOWNLOAD_PATH].data.indirected_text.text =
+ dw->path;
+ download_template->icons[ICON_DOWNLOAD_PATH].data.indirected_text.size =
+ sizeof dw->path;
+
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].data.
+ indirected_text.text = dw->path;
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].data.
+ indirected_text.size = sizeof dw->path;
+
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].flags |=
+ wimp_ICON_DELETED;
+
+ /* create and open the download window */
+ error = xwimp_create_window(download_template, &dw->window);
+ if (error) {
+ LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ free(dw);
+ return 0;
+ }
+
+ dw->prev = 0;
+ dw->next = download_window_list;
+ if (download_window_list)
+ download_window_list->prev = dw;
+ download_window_list = dw;
+
+ ro_gui_download_update_status(dw);
+
+ ro_gui_dialog_open(dw->window);
+
+ ro_gui_wimp_event_set_user_data(dw->window, dw);
+ ro_gui_wimp_event_register_mouse_click(dw->window, ro_gui_download_click);
+ ro_gui_wimp_event_register_keypress(dw->window, ro_gui_download_keypress);
+ ro_gui_wimp_event_register_close_window(dw->window, ro_gui_download_close);
+
+ /* issue the warning now, so that it appears in front of the download
+ * window! */
+ if (space_warning)
+ ro_warn_user("DownloadWarn", messages_get("NoDiscSpace"));
+
+ return dw;
+}
+
+/**
+ * Handle failed downloads.
+ *
+ * \param dw download window
+ * \param error_msg error message
+ */
+
+static void gui_download_window_error(struct gui_download_window *dw,
+ const char *error_msg)
+{
+ os_error *error;
+
+ if (dw->ctx != NULL)
+ download_context_destroy(dw->ctx);
+ dw->ctx = NULL;
+ dw->error = true;
+
+ riscos_schedule(-1, ro_gui_download_update_status_wrapper, dw);
+
+ /* place error message in status icon in red */
+ strncpy(dw->status, error_msg, sizeof dw->status);
+ error = xwimp_set_icon_state(dw->window,
+ ICON_DOWNLOAD_STATUS,
+ wimp_COLOUR_RED << wimp_ICON_FG_COLOUR_SHIFT,
+ wimp_ICON_FG_COLOUR);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ /* grey out pathname icon */
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
+ wimp_ICON_SHADED, 0);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ /* grey out file icon */
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
+ wimp_ICON_SHADED, wimp_ICON_SHADED);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ ro_gui_download_window_hide_caret(dw);
+}
+
+/**
+ * Handle received download data.
+ *
+ * \param dw download window
+ * \param data pointer to block of data received
+ * \param size size of data
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+
+static nserror gui_download_window_data(struct gui_download_window *dw,
+ const char *data, unsigned int size)
+{
+ while (true) {
+ const char *msg;
+ int unwritten;
+ os_error *error;
+
+ error = xosgbpb_writew(dw->file, (const byte *) data, size,
+ &unwritten);
+ if (error) {
+ LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ msg = error->errmess;
+
+ } else if (unwritten) {
+ LOG("xosgbpb_writew: unwritten %i", unwritten);
+ msg = messages_get("Unwritten");
+ }
+ else {
+ dw->received += size;
+ return NSERROR_OK;
+ }
+
+ ro_warn_user("SaveError", msg);
+
+ if (dw->saved) {
+ /* try to continue with the temporary file */
+ const char *temp_name = ro_gui_download_temp_name(dw);
+
+ error = ro_gui_download_move(dw, temp_name, dw->path);
+ if (!error) {
+
+ /* re-allow saving */
+ dw->saved = false;
+
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
+ wimp_ICON_SHADED, 0);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_DESTINATION,
+ wimp_ICON_DELETED, wimp_ICON_DELETED);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ error = xwimp_set_icon_state(dw->window,
+ ICON_DOWNLOAD_PATH, wimp_ICON_DELETED, 0);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ continue;
+ }
+ }
+
+ /* give up then */
+ assert(dw->ctx);
+ download_context_abort(dw->ctx);
+ gui_download_window_error(dw, msg);
+
+ return NSERROR_SAVE_FAILED;
+ }
+}
+
+
+/**
+ * Update the status text and progress bar.
+ *
+ * \param dw download window
+ */
+
+void ro_gui_download_update_status(struct gui_download_window *dw)
+{
+ char *total_size;
+ char *speed;
+ char time[20] = "?";
+ struct timeval t;
+ float dt;
+ unsigned int left;
+ float rate;
+ os_error *error;
+ int width;
+ char *local_status;
+ nserror err;
+
+ gettimeofday(&t, 0);
+ dt = (t.tv_sec + 0.000001 * t.tv_usec) - (dw->last_time.tv_sec +
+ 0.000001 * dw->last_time.tv_usec);
+ if (dt == 0)
+ dt = 0.001;
+
+ total_size = human_friendly_bytesize(max(dw->received, dw->total_size));
+
+ if (dw->ctx) {
+ char *received;
+ rate = (dw->received - dw->last_received) / dt;
+ received = human_friendly_bytesize(dw->received);
+ /* A simple 'modified moving average' download rate calculation
+ * to smooth out rate fluctuations: chosen for simplicity.
+ */
+ dw->average_points++;
+ dw->average_rate =
+ ((dw->average_points - 1) *
+ dw->average_rate + rate) /
+ dw->average_points;
+ speed = human_friendly_bytesize(dw->average_rate);
+ if (dw->total_size) {
+ float f;
+
+ if (dw->average_rate > 0) {
+ left = (dw->total_size - dw->received) /
+ dw->average_rate;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+ }
+
+ /* convert to local encoding */
+ err = utf8_to_local_encoding(
+ messages_get("Download"), 0, &local_status);
+ if (err != NSERROR_OK) {
+ /* badenc should never happen */
+ assert(err != NSERROR_BAD_ENCODING);
+ /* hide nomem error */
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("Download"),
+ received, total_size, speed, time);
+ }
+ else {
+ snprintf(dw->status, sizeof dw->status,
+ local_status,
+ received, total_size, speed, time);
+ free(local_status);
+ }
+
+ f = (float) dw->received / (float) dw->total_size;
+ width = download_progress_width * f;
+ } else {
+ left = t.tv_sec - dw->start_time.tv_sec;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+
+ err = utf8_to_local_encoding(
+ messages_get("DownloadU"), 0, &local_status);
+ if (err != NSERROR_OK) {
+ /* badenc should never happen */
+ assert(err != NSERROR_BAD_ENCODING);
+ /* hide nomem error */
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("DownloadU"),
+ received, speed, time);
+ }
+ else {
+ snprintf(dw->status, sizeof dw->status,
+ local_status,
+ received, speed, time);
+ free(local_status);
+ }
+
+ /* length unknown, stay at 0 til finished */
+ width = 0;
+ }
+ } else {
+ left = dw->last_time.tv_sec - dw->start_time.tv_sec;
+ if (left == 0)
+ left = 1;
+ rate = (float) dw->received / (float) left;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+ speed = human_friendly_bytesize(rate);
+
+ err = utf8_to_local_encoding(messages_get("Downloaded"), 0,
+ &local_status);
+ if (err != NSERROR_OK) {
+ /* badenc should never happen */
+ assert(err != NSERROR_BAD_ENCODING);
+ /* hide nomem error */
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("Downloaded"),
+ total_size, speed, time);
+ }
+ else {
+ snprintf(dw->status, sizeof dw->status, local_status,
+ total_size, speed, time);
+ free(local_status);
+ }
+
+ /* all done */
+ width = download_progress_width;
+ }
+
+ dw->last_time = t;
+ dw->last_received = dw->received;
+
+ error = xwimp_resize_icon(dw->window, ICON_DOWNLOAD_PROGRESS,
+ download_progress_x0,
+ download_progress_y0,
+ download_progress_x0 + width,
+ download_progress_y1);
+ if (error) {
+ LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_STATUS, 0, 0);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ if (dw->ctx) {
+ riscos_schedule(1000, ro_gui_download_update_status_wrapper, dw);
+ } else {
+ riscos_schedule(-1, ro_gui_download_update_status_wrapper, dw);
+ }
+}
+
+
+/**
+ * Wrapper for ro_gui_download_update_status(), suitable for riscos_schedule().
+ */
+
+void ro_gui_download_update_status_wrapper(void *p)
+{
+ ro_gui_download_update_status((struct gui_download_window *) p);
+}
+
+
+
+/**
+ * Hide the caret but preserve input focus.
+ *
+ * \param dw download window
+ */
+
+void ro_gui_download_window_hide_caret(struct gui_download_window *dw)
+{
+ wimp_caret caret;
+ os_error *error;
+
+ error = xwimp_get_caret_position(&caret);
+ if (error) {
+ LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ else if (caret.w == dw->window) {
+ error = xwimp_set_caret_position(dw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
+ if (error) {
+ LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+}
+
+
+
+
+/**
+ * Handle completed downloads.
+ *
+ * \param dw download window
+ */
+
+static void gui_download_window_done(struct gui_download_window *dw)
+{
+ os_error *error;
+
+ if (dw->ctx != NULL)
+ download_context_destroy(dw->ctx);
+ dw->ctx = NULL;
+ ro_gui_download_update_status(dw);
+
+ error = xosfind_closew(dw->file);
+ if (error) {
+ LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+ dw->file = 0;
+
+ if (dw->saved) {
+ error = xosfile_set_type(dw->path,
+ dw->file_type);
+ if (error) {
+ LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+
+ if (dw->send_dataload) {
+ ro_gui_download_send_dataload(dw);
+ }
+
+ riscos_schedule(2000, ro_gui_download_window_destroy_wrapper, dw);
+ }
+}
+
+
+/**
+ * Handle Mouse_Click events in a download window.
+ *
+ * \param pointer block returned by Wimp_Poll
+ */
+
+bool ro_gui_download_click(wimp_pointer *pointer)
+{
+ struct gui_download_window *dw;
+
+ dw = (struct gui_download_window *)ro_gui_wimp_event_get_user_data(pointer->w);
+ if ((pointer->buttons & (wimp_DRAG_SELECT | wimp_DRAG_ADJUST)) &&
+ pointer->i == ICON_DOWNLOAD_ICON &&
+ !dw->error && !dw->saved) {
+ const char *sprite = ro_gui_get_icon_string(pointer->w, pointer->i);
+ int x = pointer->pos.x, y = pointer->pos.y;
+ wimp_window_state wstate;
+ wimp_icon_state istate;
+ /* start the drag from the icon's exact location, rather than the pointer */
+ istate.w = wstate.w = pointer->w;
+ istate.i = pointer->i;
+ if (!xwimp_get_window_state(&wstate) && !xwimp_get_icon_state(&istate)) {
+ x = (istate.icon.extent.x1 + istate.icon.extent.x0)/2 +
+ wstate.visible.x0 - wstate.xscroll;
+ y = (istate.icon.extent.y1 + istate.icon.extent.y0)/2 +
+ wstate.visible.y1 - wstate.yscroll;
+ }
+ ro_mouse_drag_start(ro_gui_download_drag_end, NULL, NULL, NULL);
+ download_window_current = dw;
+ ro_gui_drag_icon(x, y, sprite);
+
+ } else if (pointer->i == ICON_DOWNLOAD_DESTINATION) {
+ char command[256] = "Filer_OpenDir ";
+ char *dot;
+
+ strncpy(command + 14, dw->path, 242);
+ command[255] = 0;
+ dot = strrchr(command, '.');
+ if (dot) {
+ os_error *error;
+ *dot = 0;
+ error = xos_cli(command);
+ if (error) {
+ LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ }
+ }
+ }
+ return true;
+}
+
+
+/**
+ * Handler Key_Press events in a download window.
+ *
+ * \param key key press returned by Wimp_Poll
+ * \return true iff key press handled
+ */
+
+bool ro_gui_download_keypress(wimp_key *key)
+{
+ struct gui_download_window *dw;
+
+ dw = (struct gui_download_window *)ro_gui_wimp_event_get_user_data(key->w);
+ switch (key->c)
+ {
+ case wimp_KEY_ESCAPE:
+ ro_gui_download_window_destroy(dw, false);
+ return true;
+
+ case wimp_KEY_RETURN: {
+ const char *name = ro_gui_get_icon_string(dw->window,
+ ICON_DOWNLOAD_PATH);
+ if (!strrchr(name, '.')) {
+ ro_warn_user("NoPathError", NULL);
+ return true;
+ }
+ ro_gui_convert_save_path(dw->path, sizeof dw->path, name);
+
+ dw->send_dataload = false;
+ if (ro_gui_download_save(dw, dw->path,
+ !nsoption_bool(confirm_overwrite)) && !dw->ctx)
+ {
+ /* finished already */
+ riscos_schedule(2000, ro_gui_download_window_destroy_wrapper, dw);
+ }
+ return true;
+ }
+ break;
+ }
+
+ /* ignore all other keypresses (F12 etc) */
+ return false;
+}
+
+
+/**
+ * Handle User_Drag_Box event for a drag from a download window.
+ *
+ * \param *drag block returned by Wimp_Poll
+ * \param *data NULL data to allow use as callback from ro_mouse.
+ */
+
+static void ro_gui_download_drag_end(wimp_dragged *drag, void *data)
+{
+ wimp_pointer pointer;
+ wimp_message message;
+ struct gui_download_window *dw = download_window_current;
+ const char *leaf;
+ os_error *error;
+
+ if (dw->saved || dw->error)
+ return;
+
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ /* ignore drags to the download window itself */
+ if (pointer.w == dw->window) return;
+
+ leaf = strrchr(dw->path, '.');
+ if (leaf)
+ leaf++;
+ else
+ leaf = dw->path;
+ ro_gui_convert_save_path(message.data.data_xfer.file_name, 212, leaf);
+
+ message.your_ref = 0;
+ message.action = message_DATA_SAVE;
+ message.data.data_xfer.w = pointer.w;
+ message.data.data_xfer.i = pointer.i;
+ message.data.data_xfer.pos.x = pointer.pos.x;
+ message.data.data_xfer.pos.y = pointer.pos.y;
+ message.data.data_xfer.est_size = dw->total_size ? dw->total_size :
+ dw->received;
+ message.data.data_xfer.file_type = dw->file_type;
+ message.size = 44 + ((strlen(message.data.data_xfer.file_name) + 4) &
+ (~3u));
+
+ error = xwimp_send_message_to_window(wimp_USER_MESSAGE, &message,
+ pointer.w, pointer.i, 0);
+ if (error) {
+ LOG("xwimp_send_message_to_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ gui_current_drag_type = GUI_DRAG_DOWNLOAD_SAVE;
+}
+
+
+/**
+ * Handle Message_DataSaveAck for a drag from a download window.
+ *
+ * \param message block returned by Wimp_Poll
+ */
+
+void ro_gui_download_datasave_ack(wimp_message *message)
+{
+ struct gui_download_window *dw = download_window_current;
+
+ dw->send_dataload = true;
+ memcpy(&dw->save_message, message, sizeof(wimp_message));
+
+ if (!ro_gui_download_save(dw, message->data.data_xfer.file_name,
+ !nsoption_bool(confirm_overwrite)))
+ return;
+
+ if (!dw->ctx) {
+ /* Ack successful completed save with message_DATA_LOAD immediately
+ to reduce the chance of the target app getting confused by it
+ being delayed */
+
+ ro_gui_download_send_dataload(dw);
+
+ riscos_schedule(2000, ro_gui_download_window_destroy_wrapper, dw);
+ }
+}
+
+
+/**
+ * Return a pathname in canonical form
+ *
+ * \param path pathnamee to be canonicalised
+ * \return ptr to pathname in malloc block, or NULL
+ */
+
+char *ro_gui_download_canonicalise(const char *path)
+{
+ os_error *error;
+ int spare = 0;
+ char *buf;
+
+ error = xosfscontrol_canonicalise_path(path, NULL, NULL, NULL, 0, &spare);
+ if (error) {
+ LOG("xosfscontrol_canonicalise_path: 0x%x: %s", error->errnum, error->errmess);
+ return NULL;
+ }
+
+ buf = malloc(1 - spare);
+ if (buf) {
+ error = xosfscontrol_canonicalise_path(path, buf, NULL, NULL,
+ 1 - spare, NULL);
+ if (error) {
+ LOG("xosfscontrol_canonicalise_path: 0x%x: %s", error->errnum, error->errmess);
+
+ free(buf);
+ return NULL;
+ }
+ }
+
+ return buf;
+}
+
+
+/**
+ * Check the available space on the medium containing the destination file,
+ * taking into account any space currently occupied by the file at its
+ * original location.
+ *
+ * \param dw download window
+ * \param dest_file destination pathname
+ * \param orig_file current pathname, NULL if no existing file
+ * \return true iff there's enough space
+ */
+
+bool ro_gui_download_check_space(struct gui_download_window *dw,
+ const char *dest_file, const char *orig_file)
+{
+ /* is there enough free space for this file? */
+ int dest_len = strlen(dest_file);
+ os_error *error;
+ int max_file;
+ bits free_lo;
+ int free_hi;
+ char *dir;
+
+ dir = malloc(dest_len + 1);
+ if (!dir) return true;
+
+ while (dest_len > 0 && dest_file[--dest_len] != '.');
+
+ memcpy(dir, dest_file, dest_len);
+ dir[dest_len] = '\0';
+
+ /* try the 64-bit variant first (RO 3.6+) */
+ error = xosfscontrol_free_space64(dir, &free_lo, &free_hi,
+ &max_file, NULL, NULL);
+ if (error) {
+ LOG("xosfscontrol_free_space64: 0x%x: %s", error->errnum, error->errmess);
+
+ free_hi = 0;
+ error = xosfscontrol_free_space(dir, (int*)&free_lo,
+ &max_file, NULL);
+ if (error) {
+ LOG("xosfscontrol_free_space: 0x%x: %s", error->errnum, error->errmess);
+ /* close our eyes and hope */
+ free(dir);
+ return true;
+ }
+ }
+
+ free(dir);
+
+ if ((bits)max_file < dw->total_size || (!free_hi && free_lo < dw->total_size)) {
+ char *dest_canon, *orig_canon;
+ bits space;
+
+ if (!orig_file || !dw->file) {
+ /* no original file to take into account */
+ return false;
+ }
+
+ space = min((bits)max_file, free_lo);
+
+ dest_canon = ro_gui_download_canonicalise(dest_file);
+ if (!dest_canon) dest_canon = (char*)dest_file;
+
+ orig_canon = ro_gui_download_canonicalise(orig_file);
+ if (!orig_canon) orig_canon = (char*)orig_file;
+
+ /* not enough space; allow for the file's original location
+ when space is tight by comparing the first part of the two
+ pathnames (and assuming the FS isn't brain damaged!) */
+
+ char *dot = strchr(orig_canon, '.');
+ if (dot && !strncasecmp(dest_canon, orig_canon, (dot + 1) - orig_canon)) {
+ int allocation;
+
+ error = xosargs_read_allocation(dw->file,
+ &allocation);
+ if (error) {
+ LOG("xosargs_read_allocation: 0x%x : %s", error->errnum, error->errmess);
+ }
+ else {
+ space += allocation;
+ }
+ }
+
+ if (dest_canon != dest_file) free(dest_canon);
+ if (orig_canon != orig_file) free(orig_canon);
+
+ if (space >= dw->total_size) {
+ /* OK, renaming should work */
+ return true;
+ }
+
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Move the downloading file to a new location and continue downloading there.
+ *
+ * \param dw download window
+ * \param dest_file new location
+ * \param src_file old location
+ * \return error iff failed to move file
+ */
+
+os_error *ro_gui_download_move(struct gui_download_window *dw,
+ const char *dest_file, const char *src_file)
+{
+ os_error *error;
+
+ /* close temporary file */
+ if (dw->file) {
+ error = xosfind_closew(dw->file);
+ dw->file = 0;
+ if (error) {
+ LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ return error;
+ }
+ }
+
+ /* move or copy temporary file to destination file */
+ error = xosfscontrol_rename(src_file, dest_file);
+ /* Errors from a filing system have number 0x1XXnn, where XX is the FS
+ * number, and nn the error number. 0x9F is "Not same disc". */
+ if (error && (error->errnum == error_BAD_RENAME ||
+ (error->errnum & 0xFF00FFu) == 0x1009Fu)) {
+ /* rename failed: copy with delete */
+ error = xosfscontrol_copy(src_file, dest_file,
+ osfscontrol_COPY_FORCE |
+ osfscontrol_COPY_DELETE |
+ osfscontrol_COPY_LOOK,
+ 0, 0, 0, 0, 0);
+ if (error) {
+ LOG("xosfscontrol_copy: 0x%x: %s", error->errnum, error->errmess);
+ return error;
+ }
+ } else if (error) {
+ LOG("xosfscontrol_rename: 0x%x: %s", error->errnum, error->errmess);
+ return error;
+ }
+
+ if (dw->ctx) {
+ /* open new destination file if still fetching */
+ error = xosfile_write(dest_file, 0xdeaddead, 0xdeaddead,
+ fileswitch_ATTR_OWNER_READ |
+ fileswitch_ATTR_OWNER_WRITE);
+ if (error) {
+ LOG("xosfile_write: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+
+ error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
+ dest_file, 0, &dw->file);
+ if (error) {
+ LOG("xosfind_openupw: 0x%x: %s", error->errnum, error->errmess);
+ return error;
+ }
+
+ error = xosargs_set_ptrw(dw->file, dw->received);
+ if (error) {
+ LOG("xosargs_set_ptrw: 0x%x: %s", error->errnum, error->errmess);
+ return error;
+ }
+
+ } else {
+ /* otherwise just set the file type */
+ error = xosfile_set_type(dest_file,
+ dw->file_type);
+ if (error) {
+ LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+ }
+
+ /* success */
+ return NULL;
+}
+
+
+/**
+ * Remember the directory containing the given file,
+ * for use in further downloads.
+ *
+ * \param path pathname of downloaded file
+ * \return none
+ */
+
+void ro_gui_download_remember_dir(const char *path)
+{
+ const char *lastdot = NULL;
+ const char *p = path;
+
+ while (*p >= 0x20) {
+ if (*p == '.') {
+ /* don't remember the directory if it's a temporary file */
+ if (!lastdot && p == path + 12 &&
+ !memcmp(path, "<Wimp$Scrap>", 12)) break;
+ lastdot = p;
+ }
+ p++;
+ }
+
+ if (lastdot) {
+ /* remember the directory */
+ char *new_dir = realloc(download_dir, (lastdot+1)-path);
+ if (new_dir) {
+ download_dir_len = lastdot - path;
+ memcpy(new_dir, path, download_dir_len);
+ new_dir[download_dir_len] = '\0';
+ download_dir = new_dir;
+ }
+ }
+}
+
+/**
+ * Start of save operation, user has specified where the file should be saved.
+ *
+ * \param dw download window
+ * \param file_name pathname of destination file
+ & \param force_overwrite true iff required to overwrite without prompting
+ * \return true iff save successfully initiated
+ */
+
+bool ro_gui_download_save(struct gui_download_window *dw,
+ const char *file_name, bool force_overwrite)
+{
+ fileswitch_object_type obj_type;
+ const char *temp_name;
+ os_error *error;
+
+ if (dw->saved || dw->error)
+ return true;
+
+ temp_name = ro_gui_download_temp_name(dw);
+
+ /* does the user want to check for collisions when saving? */
+ if (!force_overwrite) {
+ /* check whether the destination file/dir already exists */
+ error = xosfile_read_stamped(file_name, &obj_type,
+ NULL, NULL, NULL, NULL, NULL);
+ if (error) {
+ LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess);
+ return false;
+ }
+
+ switch (obj_type) {
+ case osfile_NOT_FOUND:
+ break;
+
+ case osfile_IS_FILE:
+ dw->query = query_user("OverwriteFile", NULL, &overwrite_funcs, dw,
+ messages_get("Replace"), messages_get("DontReplace"));
+ dw->query_rsn = QueryRsn_Overwrite;
+ return false;
+
+ default:
+ error = xosfile_make_error(file_name, obj_type);
+ assert(error);
+ ro_warn_user("SaveError", error->errmess);
+ return false;
+ }
+ }
+
+ if (!ro_gui_download_check_space(dw, file_name, temp_name)) {
+ ro_warn_user("SaveError", messages_get("NoDiscSpace"));
+ return false;
+ }
+
+ error = ro_gui_download_move(dw, file_name, temp_name);
+ if (error) {
+ ro_warn_user("SaveError", error->errmess);
+
+ /* try to reopen at old location so that the download can continue
+ to the temporary file */
+ error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
+ temp_name, 0, &dw->file);
+ if (error) {
+ LOG("xosfind_openupw: 0x%x: %s", error->errnum, error->errmess);
+
+ } else {
+ error = xosargs_set_ptrw(dw->file, dw->received);
+ if (error) {
+ LOG("xosargs_set_ptrw: 0x%x: %s", error->errnum, error->errmess);
+ }
+ }
+
+ if (error) {
+ if (dw->ctx)
+ download_context_abort(dw->ctx);
+ gui_download_window_error(dw, error->errmess);
+ }
+ return false;
+ }
+
+ dw->saved = true;
+ strncpy(dw->path, file_name, sizeof dw->path);
+
+ if (!dw->send_dataload || dw->save_message.data.data_xfer.est_size != -1)
+ ro_gui_download_remember_dir(file_name);
+
+ /* grey out file icon */
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
+ wimp_ICON_SHADED, wimp_ICON_SHADED);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ /* hide writeable path icon and show destination icon
+ Note: must redraw icon bounding box because the destination icon
+ has rounded edges on RISC OS Select/Adjust and doesn't
+ completely cover the writeable icon */
+
+ ro_gui_force_redraw_icon(dw->window, ICON_DOWNLOAD_PATH);
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
+ wimp_ICON_DELETED, wimp_ICON_DELETED);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ error = xwimp_set_icon_state(dw->window,
+ ICON_DOWNLOAD_DESTINATION, wimp_ICON_DELETED, 0);
+ if (error) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ ro_gui_download_window_hide_caret(dw);
+
+ return true;
+}
+
+
+/**
+ * Send DataLoad message in response to DataSaveAck, informing the
+ * target application that the transfer is complete.
+ *
+ * \param dw download window
+ */
+
+void ro_gui_download_send_dataload(struct gui_download_window *dw)
+{
+ /* Ack successful save with message_DATA_LOAD */
+ wimp_message *message = &dw->save_message;
+ os_error *error;
+
+ assert(dw->send_dataload);
+ dw->send_dataload = false;
+
+ message->action = message_DATA_LOAD;
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message_to_window(wimp_USER_MESSAGE, message,
+ message->data.data_xfer.w,
+ message->data.data_xfer.i, 0);
+ /* The window we just attempted to send a message to may
+ * have been closed before the message was sent. As we've
+ * no clean way of detecting this, we'll just detect the
+ * error return from the message send attempt and judiciously
+ * ignore it.
+ *
+ * Ideally, we would have registered to receive Message_WindowClosed
+ * and then cleared dw->send_dataload flag for the appropriate
+ * window. Unfortunately, however, a long-standing bug in the
+ * Pinboard module prevents this from being a viable solution.
+ *
+ * See http://groups.google.co.uk/group/comp.sys.acorn.tech/msg/e3fbf70d8393e6cf?dmode=source&hl=en
+ * for the rather depressing details.
+ */
+ if (error && error->errnum != error_WIMP_BAD_HANDLE) {
+ LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+
+ riscos_schedule(2000, ro_gui_download_window_destroy_wrapper, dw);
+}
+
+
+/**
+ * Handle closing of download window
+ */
+void ro_gui_download_close(wimp_w w)
+{
+ struct gui_download_window *dw;
+
+ dw = (struct gui_download_window *)ro_gui_wimp_event_get_user_data(w);
+ ro_gui_download_window_destroy(dw, false);
+}
+
+
+/**
+ * Close a download window and free any related resources.
+ *
+ * \param dw download window
+ * \param quit destroying because we're quitting the whole app
+ * \return true if window destroyed, not waiting for user confirmation
+ */
+
+bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit)
+{
+ bool safe = dw->saved && !dw->ctx;
+ os_error *error;
+
+ if (!safe && !dw->close_confirmed)
+ {
+ query_reason rsn = quit ? QueryRsn_Quit : QueryRsn_Abort;
+
+ if (dw->query != QUERY_INVALID) {
+
+ /* can we just reuse the existing query? */
+ if (rsn == dw->query_rsn) {
+ ro_gui_query_window_bring_to_front(dw->query);
+ return false;
+ }
+
+ query_close(dw->query);
+ dw->query = QUERY_INVALID;
+ }
+
+ if (quit) {
+ /* bring all download windows to the front of the desktop as
+ a convenience if there are lots of windows open */
+
+ struct gui_download_window *d = download_window_list;
+ while (d) {
+ ro_gui_dialog_open_top(d->window, NULL, 0, 0);
+ d = d->next;
+ }
+ }
+
+ dw->query_rsn = rsn;
+ dw->query = query_user(quit ? "QuitDownload" : "AbortDownload",
+ NULL, &close_funcs, dw, NULL, NULL);
+
+ return false;
+ }
+
+ riscos_schedule(-1, ro_gui_download_update_status_wrapper, dw);
+ riscos_schedule(-1, ro_gui_download_window_destroy_wrapper, dw);
+
+ /* remove from list */
+ if (dw->prev)
+ dw->prev->next = dw->next;
+ else
+ download_window_list = dw->next;
+ if (dw->next)
+ dw->next->prev = dw->prev;
+
+ /* delete window */
+ error = xwimp_delete_window(dw->window);
+ if (error) {
+ LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ ro_gui_wimp_event_finalise(dw->window);
+
+ /* close download file */
+ if (dw->file) {
+ error = xosfind_closew(dw->file);
+ if (error) {
+ LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+ }
+
+ /* delete temporary file */
+ if (!dw->saved) {
+ const char *temp_name = ro_gui_download_temp_name(dw);
+
+ error = xosfile_delete(temp_name, 0, 0, 0, 0, 0);
+ if (error) {
+ LOG("xosfile_delete: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ }
+ }
+
+ if (dw->ctx) {
+ download_context_abort(dw->ctx);
+ download_context_destroy(dw->ctx);
+ }
+
+ free(dw);
+
+ return true;
+}
+
+
+/**
+ * Wrapper for ro_gui_download_window_destroy(), suitable for riscos_schedule().
+ */
+
+void ro_gui_download_window_destroy_wrapper(void *p)
+{
+ struct gui_download_window *dw = p;
+ if (dw->query != QUERY_INVALID)
+ query_close(dw->query);
+ dw->query = QUERY_INVALID;
+ dw->close_confirmed = true;
+ ro_gui_download_window_destroy(dw, false);
+}
+
+
+/**
+ * User has opted to cancel the close, leaving the download to continue.
+ */
+
+void ro_gui_download_close_cancelled(query_id id, enum query_response res, void *p)
+{
+ struct gui_download_window *dw = p;
+ dw->query = QUERY_INVALID;
+}
+
+
+/**
+ * Download aborted, close window and tidy up.
+ */
+
+void ro_gui_download_close_confirmed(query_id id, enum query_response res, void *p)
+{
+ struct gui_download_window *dw = p;
+ dw->query = QUERY_INVALID;
+ dw->close_confirmed = true;
+ if (dw->query_rsn == QueryRsn_Quit) {
+
+ /* destroy all our downloads */
+ while (download_window_list)
+ ro_gui_download_window_destroy_wrapper(download_window_list);
+
+ /* and restart the shutdown */
+ if (ro_gui_prequit())
+ riscos_done = true;
+ }
+ else
+ ro_gui_download_window_destroy(dw, false);
+}
+
+
+/**
+ * User has opted not to overwrite the existing file.
+ */
+
+void ro_gui_download_overwrite_cancelled(query_id id, enum query_response res, void *p)
+{
+ struct gui_download_window *dw = p;
+ dw->query = QUERY_INVALID;
+}
+
+
+/**
+ * Overwrite of existing file confirmed, proceed with the save.
+ */
+
+void ro_gui_download_overwrite_confirmed(query_id id, enum query_response res, void *p)
+{
+ struct gui_download_window *dw = p;
+ dw->query = QUERY_INVALID;
+
+ if (!ro_gui_download_save(dw, dw->save_message.data.data_xfer.file_name, true))
+ return;
+
+ if (!dw->ctx) {
+ /* Ack successful completed save with message_DATA_LOAD immediately
+ to reduce the chance of the target app getting confused by it
+ being delayed */
+
+ ro_gui_download_send_dataload(dw);
+
+ riscos_schedule(2000, ro_gui_download_window_destroy_wrapper, dw);
+ }
+}
+
+
+/**
+ * Respond to PreQuit message, displaying a prompt message if we need
+ * the user to confirm the shutdown.
+ *
+ * \return true if we can shutdown straightaway
+ */
+
+bool ro_gui_download_prequit(void)
+{
+ while (download_window_list)
+ {
+ if (!ro_gui_download_window_destroy(download_window_list, true))
+ return false; /* awaiting user confirmation */
+ }
+ return true;
+}
+
+static struct gui_download_table download_table = {
+ .create = gui_download_window_create,
+ .data = gui_download_window_data,
+ .error = gui_download_window_error,
+ .done = gui_download_window_done,
+};
+
+struct gui_download_table *riscos_download_table = &download_table;
diff --git a/frontends/riscos/filetype.c b/frontends/riscos/filetype.c
new file mode 100644
index 000000000..99a44ae30
--- /dev/null
+++ b/frontends/riscos/filetype.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unixlib/local.h>
+#include "oslib/mimemap.h"
+#include "oslib/osfile.h"
+
+#include "utils/config.h"
+#include "utils/log.h"
+#include "content/content.h"
+#include "content/fetch.h"
+#include "content/hlcache.h"
+
+#include "riscos/filetype.h"
+#include "riscos/gui.h"
+
+/* type_map must be in sorted order by file_type */
+struct type_entry {
+ bits file_type;
+ char mime_type[40];
+};
+static const struct type_entry type_map[] = {
+ {0x132, "image/ico"},
+ {0x188, "application/x-shockwave-flash"},
+ {0x695, "image/gif"},
+ {0x69c, "image/x-ms-bmp"},
+ {0xaad, "image/svg+xml"},
+ {0xaff, "image/x-drawfile"},
+ {0xb60, "image/png"},
+ {0xc85, "image/jpeg"},
+ {0xd94, "image/x-artworks"},
+ {0xf78, "image/jng"},
+ {0xf79, "text/css"},
+ {0xf81, "application/javascript"},
+ {0xf83, "image/mng"},
+ {0xfaf, "text/html"},
+ {0xff9, "image/x-riscos-sprite"},
+ {0xfff, "text/plain"},
+};
+#define TYPE_MAP_COUNT (sizeof(type_map) / sizeof(type_map[0]))
+
+#define BUF_SIZE (256)
+static char type_buf[BUF_SIZE];
+
+
+static int cmp_type(const void *x, const void *y);
+
+/* exported interface documented in riscos/filetype.h */
+const char *fetch_filetype(const char *unix_path)
+{
+ struct type_entry *t;
+ unsigned int len = strlen(unix_path) + 100;
+ char *path = calloc(len, 1);
+ char *r;
+ os_error *error;
+ bits file_type, temp;
+ int objtype;
+
+ if (!path) {
+ LOG("Insufficient memory for calloc");
+ ro_warn_user("NoMemory", 0);
+ return "application/riscos";
+ }
+
+ /* convert path to RISC OS format and read file type */
+ r = __riscosify(unix_path, 0, __RISCOSIFY_NO_SUFFIX, path, len, 0);
+ if (r == 0) {
+ LOG("__riscosify failed");
+ free(path);
+ return "application/riscos";
+ }
+
+ error = xosfile_read_stamped_no_path(path, &objtype, 0, 0, 0, 0,
+ &file_type);
+ if (error) {
+ LOG("xosfile_read_stamped_no_path failed: %s", error->errmess);
+ free(path);
+ return "application/riscos";
+ }
+
+ if (objtype == osfile_IS_DIR) {
+ sprintf(type_buf, "application/x-netsurf-directory");
+ free(path);
+ return (const char *)type_buf;
+ }
+
+ /* If filetype is text or data, and the file has an extension, try to
+ * map the extension to a filetype via the MimeMap file. */
+ if (file_type == osfile_TYPE_TEXT || file_type == osfile_TYPE_DATA) {
+ char *slash = strrchr(path, '/');
+ if (slash) {
+ error = xmimemaptranslate_extension_to_filetype(
+ slash+1, &temp);
+ if (error)
+ /* ignore error and leave file_type alone */
+ LOG("xmimemaptranslate_extension_to_filetype: ""0x%x %s", error->errnum, error->errmess);
+ else
+ file_type = temp;
+ }
+ }
+
+ /* search for MIME type in our internal table */
+ t = bsearch(&file_type, type_map, TYPE_MAP_COUNT,
+ sizeof(type_map[0]), cmp_type);
+ if (t) {
+ /* found, so return it */
+ free(path);
+ return t->mime_type;
+ }
+
+ /* not in internal table, so ask MimeMap */
+ error = xmimemaptranslate_filetype_to_mime_type(file_type, type_buf);
+ if (error) {
+ LOG("0x%x %s", error->errnum, error->errmess);
+ free(path);
+ return "application/riscos";
+ }
+ /* make sure we're NULL terminated. If we're not, the MimeMap
+ * module's probably written past the end of the buffer from
+ * SVC mode. Short of rewriting MimeMap with an incompatible API,
+ * there's nothing we can do about it.
+ */
+ type_buf[BUF_SIZE - 1] = '\0';
+
+ free(path);
+
+ LOG("mime type '%s'", type_buf);
+ return (const char *)type_buf;
+
+}
+
+/* exported interface documented in riscos/filetype.h */
+char *fetch_mimetype(const char *ro_path)
+{
+ os_error *e;
+ bits filetype = 0, load;
+ int objtype;
+ char *mime = calloc(BUF_SIZE, sizeof(char));
+ char *slash;
+ struct type_entry *t;
+
+ if (!mime) {
+ LOG("Insufficient memory for calloc");
+ ro_warn_user("NoMemory", 0);
+ return 0;
+ }
+
+ e = xosfile_read_no_path(ro_path, &objtype, &load, 0, 0, 0);
+ if (e) {
+ LOG("xosfile_read_no_path: 0x%x: %s", e->errnum, e->errmess);
+ free(mime);
+ return 0;
+ }
+
+ if (objtype == osfile_IS_DIR) {
+ free(mime);
+ return 0; /* directories are pointless */
+ }
+
+ if ((load >> 20) & 0xFFF) {
+ filetype = (load>>8) & 0x000FFF;
+ }
+ else {
+ free(mime);
+ return 0; /* no idea */
+ }
+
+ /* If filetype is text and the file has an extension, try to map the
+ * extension to a filetype via the MimeMap file. */
+ slash = strrchr(ro_path, '/');
+ if (slash && filetype == osfile_TYPE_TEXT) {
+ e = xmimemaptranslate_extension_to_filetype(slash+1, &load);
+ if (e)
+ /* if we get an error here, simply ignore it and
+ * leave filetype unchanged */
+ LOG("0x%x %s", e->errnum, e->errmess);
+ else
+ filetype = load;
+ }
+
+ /* search for MIME type in our internal table */
+ t = bsearch(&filetype, type_map, TYPE_MAP_COUNT,
+ sizeof(type_map[0]), cmp_type);
+ if (t) {
+ /* found, so return it */
+ strncpy(mime, t->mime_type, BUF_SIZE);
+ return mime;
+ }
+
+ /* not in internal table, so ask MimeMap */
+ e = xmimemaptranslate_filetype_to_mime_type(filetype, mime);
+ if (e) {
+ LOG("xmimemaptranslate_filetype_to_mime_type: 0x%x: %s", e->errnum, e->errmess);
+ free(mime);
+ return 0;
+ }
+ /* make sure we're NULL terminated. If we're not, the MimeMap
+ * module's probably written past the end of the buffer from
+ * SVC mode. Short of rewriting MimeMap with an incompatible API,
+ * there's nothing we can do about it.
+ */
+ mime[BUF_SIZE - 1] = '\0';
+
+ return mime;
+}
+
+/**
+ * Comparison function for bsearch
+ */
+int cmp_type(const void *x, const void *y)
+{
+ const bits *p = x;
+ const struct type_entry *q = y;
+ return *p < q->file_type ? -1 : (*p == q->file_type ? 0 : +1);
+}
+
+/* exported interface documented in riscos/filetype.h */
+int ro_content_filetype(hlcache_handle *c)
+{
+ lwc_string *mime_type;
+ int file_type;
+
+ file_type = ro_content_filetype_from_type(content_get_type(c));
+ if (file_type != 0)
+ return file_type;
+
+ mime_type = content_get_mime_type(c);
+
+ file_type = ro_content_filetype_from_mime_type(mime_type);
+
+ lwc_string_unref(mime_type);
+
+ return file_type;
+}
+
+
+/* exported interface documented in riscos/filetype.h */
+int ro_content_native_type(hlcache_handle *c)
+{
+ switch (ro_content_filetype(c)) {
+ case FILETYPE_JPEG: /* jpeg */
+ case FILETYPE_JNG: /* jng */
+ case FILETYPE_MNG: /* mng */
+ case FILETYPE_GIF: /* gif */
+ case FILETYPE_BMP: /* bmp */
+ case FILETYPE_ICO: /* ico */
+ case FILETYPE_PNG: /* png */
+ case 0xff9: /* sprite */
+ return osfile_TYPE_SPRITE;
+ case FILETYPE_SVG: /* svg */
+ case 0xaff: /* draw */
+ return osfile_TYPE_DRAW;
+ default:
+ break;
+ }
+
+ return osfile_TYPE_DATA;
+}
+
+
+/* exported interface documented in riscos/filetype.h */
+int ro_content_filetype_from_mime_type(lwc_string *mime_type)
+{
+ int file_type, index;
+ os_error *error;
+
+ /* Search internal type map */
+ for (index = TYPE_MAP_COUNT; index > 0; index--) {
+ const struct type_entry *e = &type_map[index - 1];
+
+ if (strlen(e->mime_type) == lwc_string_length(mime_type) &&
+ strncasecmp(e->mime_type,
+ lwc_string_data(mime_type),
+ lwc_string_length(mime_type)) == 0)
+ return e->file_type;
+ }
+
+ /* Ask MimeMap module */
+ error = xmimemaptranslate_mime_type_to_filetype(
+ lwc_string_data(mime_type), (bits *) &file_type);
+ if (error)
+ file_type = 0xffd;
+
+ return file_type;
+}
+
+
+/* exported interface documented in riscos/filetype.h */
+int ro_content_filetype_from_type(content_type type) {
+ switch (type) {
+ case CONTENT_HTML: return FILETYPE_HTML;
+ case CONTENT_TEXTPLAIN: return 0xfff;
+ case CONTENT_CSS: return 0xf79;
+ default: break;
+ }
+ return 0;
+}
+
+
+/* exported interface documented in riscos/filetype.h */
+bits ro_filetype_from_unix_path(const char *unix_path)
+{
+ unsigned int len = strlen(unix_path) + 100;
+ char *path = calloc(len, 1);
+ char *r;
+ os_error *error;
+ bits file_type;
+
+ if (!path) {
+ LOG("Insufficient memory for calloc");
+ ro_warn_user("NoMemory", 0);
+ return osfile_TYPE_DATA;
+ }
+
+ /* convert path to RISC OS format and read file type */
+ r = __riscosify(unix_path, 0, __RISCOSIFY_NO_SUFFIX, path, len, 0);
+ if (r == 0) {
+ LOG("__riscosify failed");
+ free(path);
+ return osfile_TYPE_DATA;
+ }
+
+ error = xosfile_read_stamped_no_path(path, 0, 0, 0, 0, 0,
+ &file_type);
+ if (error) {
+ LOG("xosfile_read_stamped_no_path failed: %s", error->errmess);
+ free(path);
+ return osfile_TYPE_DATA;
+ }
+
+ free(path);
+
+ return file_type;
+}
+
diff --git a/frontends/riscos/filetype.h b/frontends/riscos/filetype.h
new file mode 100644
index 000000000..3ba613033
--- /dev/null
+++ b/frontends/riscos/filetype.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file riscos/filetype.h
+ * RISC OS filetpe interface.
+ */
+
+#ifndef _NETSURF_RISCOS_FILETYPE_H_
+#define _NETSURF_RISCOS_FILETYPE_H_
+
+#include "content/content_type.h"
+
+#ifndef FILETYPE_ACORN_URI
+#define FILETYPE_ACORN_URI 0xf91
+#endif
+#ifndef FILETYPE_ANT_URL
+#define FILETYPE_ANT_URL 0xb28
+#endif
+#ifndef FILETYPE_IEURL
+#define FILETYPE_IEURL 0x1ba
+#endif
+#ifndef FILETYPE_HTML
+#define FILETYPE_HTML 0xfaf
+#endif
+#ifndef FILETYPE_JNG
+#define FILETYPE_JNG 0xf78
+#endif
+#ifndef FILETYPE_CSS
+#define FILETYPE_CSS 0xf79
+#endif
+#ifndef FILETYPE_MNG
+#define FILETYPE_MNG 0xf83
+#endif
+#ifndef FILETYPE_GIF
+#define FILETYPE_GIF 0x695
+#endif
+#ifndef FILETYPE_BMP
+#define FILETYPE_BMP 0x69c
+#endif
+#ifndef FILETYPE_ICO
+#define FILETYPE_ICO 0x132
+#endif
+#ifndef FILETYPE_PNG
+#define FILETYPE_PNG 0xb60
+#endif
+#ifndef FILETYPE_JPEG
+#define FILETYPE_JPEG 0xc85
+#endif
+#ifndef FILETYPE_ARTWORKS
+#define FILETYPE_ARTWORKS 0xd94
+#endif
+#ifndef FILETYPE_SVG
+#define FILETYPE_SVG 0xaad
+#endif
+
+/**
+ * Determine the MIME type of a local file.
+ *
+ * \param unix_path Unix style path to file on disk
+ * \return Pointer to MIME type string (should not be freed) - invalidated
+ * on next call to fetch_filetype.
+ */
+const char *fetch_filetype(const char *unix_path);
+
+/**
+ * Find a MIME type for a local file
+ *
+ * \param ro_path RISC OS style path to file on disk
+ * \return MIME type string (on heap, caller should free), or NULL
+ */
+char *fetch_mimetype(const char *ro_path);
+
+/**
+ * Determine the RISC OS filetype for a content.
+ *
+ * \param h The handle of the content to examine.
+ * \return The RISC OS filetype corresponding to the content
+ */
+int ro_content_filetype(struct hlcache_handle *h);
+
+/**
+ * Determine the native RISC OS filetype to export a content as
+ *
+ * \param c The content to examine
+ * \return Native RISC OS filetype for export
+ */
+int ro_content_native_type(struct hlcache_handle *c);
+
+/**
+ * Determine the RISC OS filetype for a MIME type
+ *
+ * \param mime_type MIME type to consider
+ * \return Corresponding RISC OS filetype
+ */
+int ro_content_filetype_from_mime_type(lwc_string *mime_type);
+
+/**
+ * Determine the RISC OS filetype from a content type.
+ *
+ * \param type The content type to examine.
+ * \return The RISC OS filetype corresponding to the content, or 0 for unknown
+ */
+int ro_content_filetype_from_type(content_type type);
+
+/**
+ * Determine the type of a local file.
+ *
+ * \param unix_path Unix style path to file on disk
+ * \return File type
+ */
+bits ro_filetype_from_unix_path(const char *unix_path);
+
+#endif
diff --git a/frontends/riscos/font.c b/frontends/riscos/font.c
new file mode 100644
index 000000000..2f2ba9a35
--- /dev/null
+++ b/frontends/riscos/font.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * RISC OS implementation of Font handling.
+ *
+ * The RUfl is used to handle and render fonts.
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpreadsysinfo.h>
+
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "desktop/gui_layout.h"
+
+#include "riscos/gui.h"
+#include "riscos/font.h"
+
+
+/** desktop font, size and style being used */
+char ro_gui_desktop_font_family[80];
+int ro_gui_desktop_font_size = 12;
+rufl_style ro_gui_desktop_font_style = rufl_WEIGHT_400;
+bool no_font_blending = false;
+
+
+/**
+ * Check that at least Homerton.Medium is available.
+ */
+static void nsfont_check_fonts(void)
+{
+ char s[252];
+ font_f font;
+ os_error *error;
+
+ error = xfont_find_font("Homerton.Medium\\ELatin1",
+ 160, 160, 0, 0, &font, 0, 0);
+ if (error) {
+ if (error->errnum == error_FILE_NOT_FOUND) {
+ xwimp_start_task("TaskWindow -wimpslot 200K -quit "
+ "<NetSurf$Dir>.FixFonts", 0);
+ die("FontBadInst");
+ } else {
+ LOG("xfont_find_font: 0x%x: %s", error->errnum, error->errmess);
+ snprintf(s, sizeof s, messages_get("FontError"),
+ error->errmess);
+ die(s);
+ }
+ }
+
+ error = xfont_lose_font(font);
+ if (error) {
+ LOG("xfont_lose_font: 0x%x: %s", error->errnum, error->errmess);
+ snprintf(s, sizeof s, messages_get("FontError"),
+ error->errmess);
+ die(s);
+ }
+}
+
+
+/**
+ * Check that a font option is valid, and fix it if not.
+ *
+ * \param option pointer to option, as used by options.[ch]
+ * \param family font family to use if option is not set, or the set
+ * family is not available
+ * \param fallback font family to use if family is not available either
+ */
+static void nsfont_check_option(char **option, const char *family,
+ const char *fallback)
+{
+ if (*option && !nsfont_exists(*option)) {
+ free(*option);
+ *option = 0;
+ }
+ if (!*option) {
+ if (nsfont_exists(family))
+ *option = strdup(family);
+ else
+ *option = strdup(fallback);
+ }
+}
+
+
+/**
+ * Initialize font handling.
+ *
+ * Exits through die() on error.
+ */
+void nsfont_init(void)
+{
+ const char *fallback;
+ rufl_code code;
+
+ nsfont_check_fonts();
+
+ LOG("Initialise RUfl");
+ code = rufl_init();
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR)
+ LOG("rufl_init: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ else
+ LOG("rufl_init: 0x%x", code);
+ die("The Unicode font library could not be initialized. "
+ "Please report this to the developers.");
+ }
+ LOG("RUfl initialised");
+
+ if (rufl_family_list_entries == 0)
+ die("No fonts could be found. At least one font must be "
+ "installed.");
+
+ fallback = nsfont_fallback_font();
+
+ nsfont_check_option(&nsoption_charp(font_sans), "Homerton", fallback);
+ nsfont_check_option(&nsoption_charp(font_serif), "Trinity", fallback);
+ nsfont_check_option(&nsoption_charp(font_mono), "Corpus", fallback);
+ nsfont_check_option(&nsoption_charp(font_cursive), "Churchill", fallback);
+ nsfont_check_option(&nsoption_charp(font_fantasy), "Sassoon", fallback);
+
+ if (nsoption_int(font_default) != PLOT_FONT_FAMILY_SANS_SERIF &&
+ nsoption_int(font_default) != PLOT_FONT_FAMILY_SERIF &&
+ nsoption_int(font_default) != PLOT_FONT_FAMILY_MONOSPACE &&
+ nsoption_int(font_default) != PLOT_FONT_FAMILY_CURSIVE &&
+ nsoption_int(font_default) != PLOT_FONT_FAMILY_FANTASY) {
+ nsoption_set_int(font_default, PLOT_FONT_FAMILY_SANS_SERIF);
+ }
+}
+
+
+/**
+ * Retrieve the fallback font name
+ *
+ * \return Fallback font name
+ */
+const char *nsfont_fallback_font(void)
+{
+ const char *fallback = "Homerton";
+
+ if (!nsfont_exists(fallback)) {
+ LOG("Homerton not found, dumping RUfl family list");
+ for (unsigned int i = 0; i < rufl_family_list_entries; i++) {
+ LOG("'%s'", rufl_family_list[i]);
+ }
+ fallback = rufl_family_list[0];
+ }
+
+ return fallback;
+}
+
+
+/**
+ * bsearch comparison routine
+ */
+static int nsfont_list_cmp(const void *keyval, const void *datum)
+{
+ const char *key = keyval;
+ const char * const *entry = datum;
+ return strcasecmp(key, *entry);
+}
+
+
+/**
+ * Check if a font family is available.
+ *
+ * \param font_family name of font family
+ * \return true if the family is available
+ */
+bool nsfont_exists(const char *font_family)
+{
+ if (bsearch(font_family, rufl_family_list,
+ rufl_family_list_entries, sizeof rufl_family_list[0],
+ nsfont_list_cmp))
+ return true;
+ return false;
+}
+
+
+/**
+ * Measure the width of a string.
+ *
+ * \param fstyle plot style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param width updated to width of string[0..length)
+ * \return true on success, false on error and error reported
+ */
+static nserror
+ro_font_width(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int *width)
+{
+ const char *font_family;
+ unsigned int font_size;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *width = 0;
+ return NSERROR_OK;
+ }
+
+ code = rufl_width(font_family, font_style, font_size,
+ string, length,
+ width);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR)
+ LOG("rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ else
+ LOG("rufl_width: 0x%x", code);
+/* ro_warn_user("MiscError", "font error"); */
+ *width = 0;
+ return NSERROR_INVALID;
+ }
+
+ *width /= 2;
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate to search for
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+static nserror
+ro_font_position(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ const char *font_family;
+ unsigned int font_size;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *char_offset = 0;
+ *actual_x = 0;
+ return NSERROR_OK;
+ }
+
+ code = rufl_x_to_offset(font_family, font_style, font_size,
+ string, length,
+ x * 2, char_offset, actual_x);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR)
+ LOG("rufl_x_to_offset: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ else
+ LOG("rufl_x_to_offset: 0x%x", code);
+/* ro_warn_user("MiscError", "font error"); */
+ *char_offset = 0;
+ *actual_x = 0;
+ return NSERROR_INVALID;
+ }
+
+ *actual_x /= 2;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string, in bytes
+ * \param x width available
+ * \param char_offset updated to offset in string of actual_x, [1..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ *
+ * On exit, char_offset indicates first character after split point.
+ *
+ * Note: char_offset of 0 should never be returned.
+ *
+ * Returns:
+ * char_offset giving split point closest to x, where actual_x <= x
+ * else
+ * char_offset giving split point closest to x, where actual_x > x
+ *
+ * Returning char_offset == length means no split possible
+ */
+static nserror
+ro_font_split(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ const char *font_family;
+ unsigned int font_size;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *char_offset = 0;
+ *actual_x = 0;
+ return NSERROR_OK;
+ }
+
+ code = rufl_split(font_family, font_style, font_size,
+ string, length,
+ x * 2, char_offset, actual_x);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR) {
+ LOG("rufl_split: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
+ rufl_fm_error->errnum, rufl_fm_error->errmess);
+ } else {
+ LOG("rufl_split: 0x%x", code);
+ }
+/* ro_warn_user("MiscError", "font error"); */
+ *char_offset = 0;
+ *actual_x = 0;
+ return NSERROR_INVALID;
+ }
+
+ if (*char_offset != length) {
+ /* we found something to split at */
+ size_t orig = *char_offset;
+
+ /* ensure a space at <= the split point we found */
+ while (*char_offset && string[*char_offset] != ' ') {
+ (*char_offset)--;
+ }
+
+ /* nothing valid found <= split point, advance to next space */
+ if (*char_offset == 0) {
+ *char_offset = orig;
+ while ((*char_offset != length) &&
+ (string[*char_offset] != ' ')) {
+ (*char_offset)++;
+ }
+ }
+ }
+
+ code = rufl_width(font_family, font_style, font_size,
+ string, *char_offset,
+ actual_x);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR) {
+ LOG("rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum, rufl_fm_error->errmess);
+ } else {
+ LOG("rufl_width: 0x%x", code);
+ }
+/* ro_warn_user("MiscError", "font error"); */
+ *char_offset = 0;
+ *actual_x = 0;
+ return NSERROR_INVALID;
+ }
+
+ *actual_x /= 2;
+ return NSERROR_OK;
+}
+
+
+/**
+ * Paint a string.
+ *
+ * \param fstyle plot style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate
+ * \param y y coordinate
+ * \return true on success, false on error and error reported
+ */
+bool nsfont_paint(const plot_font_style_t *fstyle, const char *string,
+ size_t length, int x, int y)
+{
+ const char *font_family;
+ unsigned int font_size;
+ unsigned int flags = rufl_BLEND_FONT;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0)
+ return true;
+
+ if (no_font_blending || print_active)
+ flags = 0;
+
+ code = rufl_paint(font_family, font_style, font_size,
+ string, length, x, y, flags);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR) {
+ LOG("rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ } else {
+ LOG("rufl_paint: 0x%x", code);
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Convert a font style to a font family, size and rufl_style.
+ *
+ * \param fstyle plot style for this text
+ * \param font_family updated to font family
+ * \param font_size updated to font size
+ * \param font_style updated to font style
+ */
+void nsfont_read_style(const plot_font_style_t *fstyle,
+ const char **font_family, unsigned int *font_size,
+ rufl_style *font_style)
+{
+ static const rufl_style weight_table[] = {
+ rufl_WEIGHT_100,
+ rufl_WEIGHT_200,
+ rufl_WEIGHT_300,
+ rufl_WEIGHT_400,
+ rufl_WEIGHT_500,
+ rufl_WEIGHT_600,
+ rufl_WEIGHT_700,
+ rufl_WEIGHT_800,
+ rufl_WEIGHT_900
+ };
+
+ *font_size = (fstyle->size * 16) / FONT_SIZE_SCALE;
+ if (1600 < *font_size)
+ *font_size = 1600;
+
+ switch (fstyle->family) {
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ *font_family = nsoption_charp(font_sans);
+ break;
+ case PLOT_FONT_FAMILY_SERIF:
+ *font_family = nsoption_charp(font_serif);
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ *font_family = nsoption_charp(font_mono);
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ *font_family = nsoption_charp(font_cursive);
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ *font_family = nsoption_charp(font_fantasy);
+ break;
+ default:
+ *font_family = nsoption_charp(font_sans);
+ break;
+ }
+
+ if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) {
+ *font_style = rufl_SLANTED;
+ } else {
+ *font_style = 0;
+ }
+
+ *font_style |= weight_table[(fstyle->weight / 100) - 1];
+}
+
+
+/**
+ * Looks up the current desktop font and converts that to a family name,
+ * font size and style flags suitable for passing directly to rufl
+ *
+ * \param family buffer to receive font family
+ * \param family_size buffer size
+ * \param psize receives the font size in 1/16 points
+ * \param pstyle receives the style settings to be passed to rufl
+ */
+static void
+ro_gui_wimp_desktop_font(char *family,
+ size_t family_size,
+ int *psize,
+ rufl_style *pstyle)
+{
+ rufl_style style = rufl_WEIGHT_400;
+ os_error *error;
+ int ptx, pty;
+ font_f font_handle;
+ int used;
+
+ assert(family);
+ assert(20 < family_size);
+ assert(psize);
+ assert(pstyle);
+
+ error = xwimpreadsysinfo_font(&font_handle, NULL);
+ if (error) {
+ LOG("xwimpreadsysinfo_font: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ goto failsafe;
+ }
+
+ if (font_handle == font_SYSTEM) {
+ /* Er, yeah; like that's ever gonna work with RUfl */
+ goto failsafe;
+ }
+
+ error = xfont_read_identifier(font_handle, NULL, &used);
+ if (error) {
+ LOG("xfont_read_identifier: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ goto failsafe;
+ }
+
+ if (family_size < (size_t) used + 1) {
+ LOG("desktop font name too long");
+ goto failsafe;
+ }
+
+ error = xfont_read_defn(font_handle, (byte *) family,
+ &ptx, &pty, NULL, NULL, NULL, NULL);
+ if (error) {
+ LOG("xfont_read_defn: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ goto failsafe;
+ }
+
+ for (size_t i = 0; i != (size_t) used; i++) {
+ if (family[i] < ' ') {
+ family[i] = 0;
+ break;
+ }
+ }
+
+ LOG("desktop font \"%s\"", family);
+
+ if (strcasestr(family, ".Medium"))
+ style = rufl_WEIGHT_500;
+ else if (strcasestr(family, ".Bold"))
+ style = rufl_WEIGHT_700;
+ if (strcasestr(family, ".Italic") || strcasestr(family, ".Oblique"))
+ style |= rufl_SLANTED;
+
+ char *dot = strchr(family, '.');
+ if (dot)
+ *dot = 0;
+
+ *psize = max(ptx, pty);
+ *pstyle = style;
+
+ LOG("family \"%s\", size %i, style %i", family, *psize, style);
+
+ return;
+
+failsafe:
+ strcpy(family, "Homerton");
+ *psize = 12*16;
+ *pstyle = rufl_WEIGHT_400;
+}
+
+
+/**
+ * Retrieve the current desktop font family, size and style from
+ * the WindowManager in a form suitable for passing to rufl
+ */
+void ro_gui_wimp_get_desktop_font(void)
+{
+ ro_gui_wimp_desktop_font(ro_gui_desktop_font_family,
+ sizeof(ro_gui_desktop_font_family),
+ &ro_gui_desktop_font_size,
+ &ro_gui_desktop_font_style);
+}
+
+
+static struct gui_layout_table layout_table = {
+ .width = ro_font_width,
+ .position = ro_font_position,
+ .split = ro_font_split,
+};
+
+struct gui_layout_table *riscos_layout_table = &layout_table;
diff --git a/frontends/riscos/font.h b/frontends/riscos/font.h
new file mode 100644
index 000000000..0319a7ee3
--- /dev/null
+++ b/frontends/riscos/font.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file riscos/font.h
+ * RISC OS font interface.
+ */
+
+#ifndef _NETSURF_RISCOS_FONT_H_
+#define _NETSURF_RISCOS_FONT_H_
+
+#include <rufl.h>
+
+struct gui_layout_table *riscos_layout_table;
+
+/** desktop font, size and style being used */
+extern char ro_gui_desktop_font_family[];
+extern int ro_gui_desktop_font_size;
+extern rufl_style ro_gui_desktop_font_style;
+
+void nsfont_init(void);
+bool nsfont_exists(const char *font_family);
+const char *nsfont_fallback_font(void);
+bool nsfont_paint(const plot_font_style_t *fstyle, const char *string,
+ size_t length, int x, int y);
+void nsfont_read_style(const plot_font_style_t *fstyle,
+ const char **font_family, unsigned int *font_size,
+ rufl_style *font_style);
+void ro_gui_wimp_get_desktop_font(void);
+
+#endif
diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c
new file mode 100644
index 000000000..c469847e0
--- /dev/null
+++ b/frontends/riscos/global_history.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Global history (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "oslib/wimp.h"
+#include "oslib/wimpspriteop.h"
+
+#include "content/urldb.h"
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+#include "utils/log.h"
+#include "desktop/global_history.h"
+#include "desktop/tree.h"
+#include "desktop/gui_window.h"
+
+#include "riscos/dialog.h"
+#include "riscos/global_history.h"
+#include "riscos/gui.h"
+#include "riscos/menus.h"
+#include "riscos/save.h"
+#include "riscos/toolbar.h"
+#include "riscos/treeview.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+
+static void ro_gui_global_history_toolbar_update_buttons(void);
+static void ro_gui_global_history_toolbar_save_buttons(char *config);
+static bool ro_gui_global_history_menu_prepare(wimp_w w, wimp_i i,
+ wimp_menu *menu, wimp_pointer *pointer);
+static void ro_gui_global_history_menu_warning(wimp_w w, wimp_i i,
+ wimp_menu *menu, wimp_selection *selection, menu_action action);
+static bool ro_gui_global_history_menu_select(wimp_w w, wimp_i i,
+ wimp_menu *menu, wimp_selection *selection, menu_action action);
+static void ro_gui_global_history_toolbar_click(button_bar_action action);
+
+struct ro_treeview_callbacks ro_global_history_treeview_callbacks = {
+ ro_gui_global_history_toolbar_click,
+ ro_gui_global_history_toolbar_update_buttons,
+ ro_gui_global_history_toolbar_save_buttons
+};
+
+/* The RISC OS global history window, toolbar and treeview data */
+
+static struct ro_global_history_window {
+ wimp_w window;
+ struct toolbar *toolbar;
+ ro_treeview *tv;
+ wimp_menu *menu;
+} global_history_window;
+
+/**
+ * Pre-Initialise the global history tree. This is called for things that
+ * need to be done at the gui_init() stage, such as loading templates.
+ */
+
+void ro_gui_global_history_preinitialise(void)
+{
+ /* Create our window. */
+
+ global_history_window.window = ro_gui_dialog_create("tree");
+ ro_gui_set_window_title(global_history_window.window,
+ messages_get("GlobalHistory"));
+}
+
+/**
+ * Initialise global history tree, at the gui_init2() stage.
+ */
+
+void ro_gui_global_history_postinitialise(void)
+{
+ /* Create our toolbar. */
+
+ global_history_window.toolbar = ro_toolbar_create(NULL,
+ global_history_window.window,
+ THEME_STYLE_GLOBAL_HISTORY_TOOLBAR, TOOLBAR_FLAGS_NONE,
+ ro_treeview_get_toolbar_callbacks(), NULL,
+ "HelpGHistoryToolbar");
+ if (global_history_window.toolbar != NULL) {
+ ro_toolbar_add_buttons(global_history_window.toolbar,
+ global_history_toolbar_buttons,
+ nsoption_charp(toolbar_history));
+ ro_toolbar_rebuild(global_history_window.toolbar);
+ }
+
+ /* Create the treeview with the window and toolbar. */
+
+ global_history_window.tv =
+ ro_treeview_create(global_history_window.window,
+ global_history_window.toolbar,
+ &ro_global_history_treeview_callbacks,
+ TREE_HISTORY);
+ if (global_history_window.tv == NULL) {
+ LOG("Failed to allocate treeview");
+ return;
+ }
+
+ ro_toolbar_update_client_data(global_history_window.toolbar,
+ global_history_window.tv);
+
+ /* Build the global history window menu. */
+
+ static const struct ns_menu global_history_definition = {
+ "History", {
+ { "History", NO_ACTION, 0 },
+ { "_History.Export", HISTORY_EXPORT, &dialog_saveas },
+ { "History.Expand", TREE_EXPAND_ALL, 0 },
+ { "History.Expand.All", TREE_EXPAND_ALL, 0 },
+ { "History.Expand.Folders", TREE_EXPAND_FOLDERS, 0 },
+ { "History.Expand.Links", TREE_EXPAND_LINKS, 0 },
+ { "History.Collapse", TREE_COLLAPSE_ALL, 0 },
+ { "History.Collapse.All", TREE_COLLAPSE_ALL, 0 },
+ { "History.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 },
+ { "History.Collapse.Links", TREE_COLLAPSE_LINKS, 0 },
+ { "History.Toolbars", NO_ACTION, 0 },
+ { "_History.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "History.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 },
+ { "Selection", TREE_SELECTION, 0 },
+ { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 },
+ { "Selection.Delete", TREE_SELECTION_DELETE, 0 },
+ { "SelectAll", TREE_SELECT_ALL, 0 },
+ { "Clear", TREE_CLEAR_SELECTION, 0 },
+ {NULL, 0, 0}
+ }
+ };
+ global_history_window.menu = ro_gui_menu_define_menu(
+ &global_history_definition);
+
+ ro_gui_wimp_event_register_menu(global_history_window.window,
+ global_history_window.menu, false, false);
+ ro_gui_wimp_event_register_menu_prepare(global_history_window.window,
+ ro_gui_global_history_menu_prepare);
+ ro_gui_wimp_event_register_menu_selection(global_history_window.window,
+ ro_gui_global_history_menu_select);
+ ro_gui_wimp_event_register_menu_warning(global_history_window.window,
+ ro_gui_global_history_menu_warning);
+}
+
+/**
+ * Destroy the global history window.
+ */
+
+void ro_gui_global_history_destroy(void)
+{
+ if (global_history_window.tv == NULL)
+ return;
+
+ ro_treeview_destroy(global_history_window.tv);
+}
+
+/**
+ * Open the global history window.
+ */
+
+void ro_gui_global_history_open(void)
+{
+ ro_gui_global_history_toolbar_update_buttons();
+
+ if (!ro_gui_dialog_open_top(global_history_window.window,
+ global_history_window.toolbar, 600, 800)) {
+ ro_treeview_set_origin(global_history_window.tv, 0,
+ -(ro_toolbar_height(
+ global_history_window.toolbar)));
+ }
+}
+
+/**
+ * Handle toolbar button clicks.
+ *
+ * \param action The action to handle
+ */
+
+void ro_gui_global_history_toolbar_click(button_bar_action action)
+{
+ switch (action) {
+ case TOOLBAR_BUTTON_DELETE:
+ global_history_keypress(NS_KEY_DELETE_LEFT);
+ break;
+
+ case TOOLBAR_BUTTON_EXPAND:
+ global_history_expand(false);
+ break;
+
+ case TOOLBAR_BUTTON_COLLAPSE:
+ global_history_contract(false);
+ break;
+
+ case TOOLBAR_BUTTON_OPEN:
+ global_history_expand(true);
+ break;
+
+ case TOOLBAR_BUTTON_CLOSE:
+ global_history_contract(true);
+ break;
+
+ case TOOLBAR_BUTTON_LAUNCH:
+ global_history_keypress(NS_KEY_CR);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Update the button state in the global history toolbar.
+ */
+
+void ro_gui_global_history_toolbar_update_buttons(void)
+{
+ ro_toolbar_set_button_shaded_state(global_history_window.toolbar,
+ TOOLBAR_BUTTON_DELETE,
+ !global_history_has_selection());
+
+ ro_toolbar_set_button_shaded_state(global_history_window.toolbar,
+ TOOLBAR_BUTTON_LAUNCH,
+ !global_history_has_selection());
+}
+
+
+/**
+ * Save a new button arrangement in the global history toolbar.
+ *
+ * \param *config The new button configuration string.
+ */
+
+void ro_gui_global_history_toolbar_save_buttons(char *config)
+{
+ nsoption_set_charp(toolbar_history, config);
+ ro_gui_save_options();
+}
+
+
+/**
+ * Prepare the global history menu for opening
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu about to be opened.
+ * \param *pointer Pointer to the relevant wimp event block, or
+ * NULL for an Adjust click.
+ * \return true if the event was handled; else false.
+ */
+
+bool ro_gui_global_history_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_pointer *pointer)
+{
+ bool selection;
+
+ if (menu != global_history_window.menu)
+ return false;
+
+ selection = global_history_has_selection();
+
+ ro_gui_menu_set_entry_shaded(global_history_window.menu,
+ TREE_SELECTION, !selection);
+ ro_gui_menu_set_entry_shaded(global_history_window.menu,
+ TREE_CLEAR_SELECTION, !selection);
+
+ ro_gui_save_prepare(GUI_SAVE_HISTORY_EXPORT_HTML,
+ NULL, NULL, NULL, NULL);
+
+ ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS,
+ ro_toolbar_menu_option_shade(
+ global_history_window.toolbar));
+ ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS,
+ ro_toolbar_menu_buttons_tick(
+ global_history_window.toolbar));
+
+ ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT,
+ ro_toolbar_menu_edit_shade(
+ global_history_window.toolbar));
+ ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT,
+ ro_toolbar_menu_edit_tick(
+ global_history_window.toolbar));
+
+ return true;
+}
+
+/**
+ * Handle submenu warnings for the global_hostory menu
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu to which the warning applies.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ */
+
+void ro_gui_global_history_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ /* Do nothing */
+}
+
+/**
+ * Handle selections from the global history menu
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param *menu The menu from which the selection was made.
+ * \param *selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
+ */
+
+bool ro_gui_global_history_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
+ wimp_selection *selection, menu_action action)
+{
+ switch (action) {
+ case HISTORY_EXPORT:
+ ro_gui_dialog_open_persistent(w, dialog_saveas, true);
+ return true;
+ case TREE_EXPAND_ALL:
+ global_history_expand(false);
+ return true;
+ case TREE_EXPAND_FOLDERS:
+ global_history_expand(true);
+ return true;
+ case TREE_EXPAND_LINKS:
+ global_history_expand(false);
+ return true;
+ case TREE_COLLAPSE_ALL:
+ global_history_contract(true);
+ return true;
+ case TREE_COLLAPSE_FOLDERS:
+ global_history_contract(true);
+ return true;
+ case TREE_COLLAPSE_LINKS:
+ global_history_contract(false);
+ return true;
+ case TREE_SELECTION_LAUNCH:
+ global_history_keypress(NS_KEY_CR);
+ return true;
+ case TREE_SELECTION_DELETE:
+ global_history_keypress(NS_KEY_DELETE_LEFT);
+ return true;
+ case TREE_SELECT_ALL:
+ global_history_keypress(NS_KEY_SELECT_ALL);
+ return true;
+ case TREE_CLEAR_SELECTION:
+ global_history_keypress(NS_KEY_CLEAR_SELECTION);
+ return true;
+ case TOOLBAR_BUTTONS:
+ ro_toolbar_set_display_buttons(global_history_window.toolbar,
+ !ro_toolbar_get_display_buttons(
+ global_history_window.toolbar));
+ return true;
+ case TOOLBAR_EDIT:
+ ro_toolbar_toggle_edit(global_history_window.toolbar);
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+/**
+ * Check if a particular window handle is the global history window
+ *
+ * \param window the window in question
+ * \return true if this window is the global history
+ */
+
+bool ro_gui_global_history_check_window(wimp_w window)
+{
+ if (global_history_window.window == window)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Check if a particular menu handle is the global history menu
+ *
+ * \param *menu The menu in question.
+ * \return true if this menu is the global history menu
+ */
+
+bool ro_gui_global_history_check_menu(wimp_menu *menu)
+{
+ if (global_history_window.menu == menu)
+ return true;
+ else
+ return false;
+}
+
diff --git a/frontends/riscos/global_history.h b/frontends/riscos/global_history.h
new file mode 100644
index 000000000..6f5ba11eb
--- /dev/null
+++ b/frontends/riscos/global_history.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2010 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Global history (interface).
+ */
+
+#ifndef _NETSURF_RISCOS_GLOBALHISTORY_H_
+#define _NETSURF_RISCOS_GLOBALHISTORY_H_
+
+#include "riscos/menus.h"
+
+void ro_gui_global_history_preinitialise(void);
+void ro_gui_global_history_postinitialise(void);
+void ro_gui_global_history_destroy(void);
+void ro_gui_global_history_open(void);
+void ro_gui_global_history_save(void);
+bool ro_gui_global_history_check_window(wimp_w window);
+bool ro_gui_global_history_check_menu(wimp_menu *menu);
+
+#endif
+
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
new file mode 100644
index 000000000..309f27bdb
--- /dev/null
+++ b/frontends/riscos/gui.c
@@ -0,0 +1,2522 @@
+/*
+ * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ * Copyright 2004-2008 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
+ * Copyright 2004-2009 John Tytgat <joty@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <unixlib/local.h>
+#include <fpu_control.h>
+#include <oslib/help.h>
+#include <oslib/uri.h>
+#include <oslib/inetsuite.h>
+#include <oslib/pdriver.h>
+#include <oslib/osfile.h>
+#include <oslib/hourglass.h>
+#include <oslib/osgbpb.h>
+#include <oslib/osbyte.h>
+#include <oslib/osmodule.h>
+#include <oslib/osfscontrol.h>
+
+#include "utils/utils.h"
+#include "utils/nsoption.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/file.h"
+#include "utils/filename.h"
+#include "utils/url.h"
+#include "utils/corestrings.h"
+#include "desktop/gui_fetch.h"
+#include "desktop/gui_misc.h"
+#include "desktop/save_complete.h"
+#include "desktop/treeview.h"
+#include "desktop/netsurf.h"
+#include "desktop/browser.h"
+#include "content/urldb.h"
+#include "content/hlcache.h"
+#include "content/backing_store.h"
+
+#include "riscos/gui.h"
+#include "riscos/bitmap.h"
+#include "riscos/wimputils.h"
+#include "riscos/hotlist.h"
+#include "riscos/buffer.h"
+#include "riscos/textselection.h"
+#include "riscos/print.h"
+#include "riscos/save.h"
+#include "riscos/dialog.h"
+#include "riscos/wimp.h"
+#include "riscos/message.h"
+#include "riscos/help.h"
+#include "riscos/query.h"
+#include "riscos/window.h"
+#include "riscos/iconbar.h"
+#include "riscos/sslcert.h"
+#include "riscos/global_history.h"
+#include "riscos/cookies.h"
+#include "riscos/wimp_event.h"
+#include "riscos/uri.h"
+#include "riscos/url_protocol.h"
+#include "riscos/mouse.h"
+#include "riscos/ucstables.h"
+#include "riscos/filetype.h"
+#include "riscos/font.h"
+#include "riscos/toolbar.h"
+#include "riscos/content-handlers/artworks.h"
+#include "riscos/content-handlers/draw.h"
+#include "riscos/content-handlers/sprite.h"
+
+bool riscos_done = false;
+
+extern bool ro_plot_patterned_lines;
+
+int os_version = 0;
+
+const char * const __dynamic_da_name = "NetSurf"; /**< For UnixLib. */
+int __dynamic_da_max_size = 128 * 1024 * 1024; /**< For UnixLib. */
+int __feature_imagefs_is_file = 1; /**< For UnixLib. */
+/* default filename handling */
+int __riscosify_control = __RISCOSIFY_NO_SUFFIX |
+ __RISCOSIFY_NO_REVERSE_SUFFIX;
+#ifndef __ELF__
+extern int __dynamic_num;
+#endif
+
+const char * NETSURF_DIR;
+
+static const char *task_name = "NetSurf";
+#define CHOICES_PREFIX "<Choices$Write>.WWW.NetSurf."
+
+ro_gui_drag_type gui_current_drag_type;
+wimp_t task_handle; /**< RISC OS wimp task handle. */
+static clock_t gui_last_poll; /**< Time of last wimp_poll. */
+osspriteop_area *gui_sprites; /**< Sprite area containing pointer and hotlist sprites */
+
+#define DIR_SEP ('.')
+
+/**
+ * Accepted wimp user messages.
+ */
+static ns_wimp_message_list task_messages = {
+ message_HELP_REQUEST,
+ {
+ message_DATA_SAVE,
+ message_DATA_SAVE_ACK,
+ message_DATA_LOAD,
+ message_DATA_LOAD_ACK,
+ message_DATA_OPEN,
+ message_PRE_QUIT,
+ message_SAVE_DESKTOP,
+ message_MENU_WARNING,
+ message_MENUS_DELETED,
+ message_WINDOW_INFO,
+ message_CLAIM_ENTITY,
+ message_DATA_REQUEST,
+ message_DRAGGING,
+ message_DRAG_CLAIM,
+ message_MODE_CHANGE,
+ message_PALETTE_CHANGE,
+ message_FONT_CHANGED,
+ message_URI_PROCESS,
+ message_URI_RETURN_RESULT,
+ message_INET_SUITE_OPEN_URL,
+#ifdef WITH_PLUGIN
+ message_PLUG_IN_OPENING,
+ message_PLUG_IN_CLOSED,
+ message_PLUG_IN_RESHAPE_REQUEST,
+ message_PLUG_IN_FOCUS,
+ message_PLUG_IN_URL_ACCESS,
+ message_PLUG_IN_STATUS,
+ message_PLUG_IN_BUSY,
+ message_PLUG_IN_STREAM_NEW,
+ message_PLUG_IN_STREAM_WRITE,
+ message_PLUG_IN_STREAM_WRITTEN,
+ message_PLUG_IN_STREAM_DESTROY,
+ message_PLUG_IN_OPEN,
+ message_PLUG_IN_CLOSE,
+ message_PLUG_IN_RESHAPE,
+ message_PLUG_IN_STREAM_AS_FILE,
+ message_PLUG_IN_NOTIFY,
+ message_PLUG_IN_ABORT,
+ message_PLUG_IN_ACTION,
+ /* message_PLUG_IN_INFORMED, (not provided by oslib) */
+#endif
+ message_PRINT_SAVE,
+ message_PRINT_ERROR,
+ message_PRINT_TYPE_ODD,
+ message_HOTLIST_ADD_URL,
+ message_HOTLIST_CHANGED,
+ 0
+ }
+};
+
+
+static struct
+{
+ int width; /* in OS units */
+ int height;
+} screen_info;
+
+
+/**
+ * Callback to translate resource to full url for RISC OS.
+ *
+ * Transforms a resource: path into a full URL. The returned URL is
+ * used as the target for a redirect. The caller takes ownership of
+ * the returned nsurl including unrefing it when finished with it.
+ *
+ * \param path The path of the resource to locate.
+ * \return A string containing the full URL of the target object or
+ * NULL if no suitable resource can be found.
+ */
+static nsurl *gui_get_resource_url(const char *path)
+{
+ static const char base_url[] = "file:///NetSurf:/Resources/";
+ size_t path_len, length;
+ char *raw;
+ nsurl *url = NULL;
+
+ /* Map paths first */
+ if (strcmp(path, "adblock.css") == 0) {
+ path = "AdBlock";
+
+ } else if (strcmp(path, "default.css") == 0) {
+ path = "CSS";
+
+ } else if (strcmp(path, "quirks.css") == 0) {
+ path = "Quirks";
+
+ } else if (strcmp(path, "favicon.ico") == 0) {
+ path = "Icons/content.png";
+
+ } else if (strcmp(path, "user.css") == 0) {
+ /* Special case; this file comes from Choices: */
+ nsurl_create("file:///Choices:WWW/NetSurf/User", &url);
+ return url;
+ }
+
+ path_len = strlen(path);
+
+ /* Find max URL length */
+ length = SLEN(base_url) + SLEN("xx/") + path_len + 1;
+
+ raw = malloc(length);
+ if (raw != NULL) {
+ /* Insert base URL */
+ char *ptr = memcpy(raw, base_url, SLEN(base_url));
+ ptr += SLEN(base_url);
+
+ /* Add language directory to URL, for translated files */
+ /* TODO: handle non-en langauages
+ * handle non-html translated files */
+ if (path_len > SLEN(".html") &&
+ strncmp(path + path_len - SLEN(".html"),
+ ".html", SLEN(".html")) == 0) {
+ memcpy(ptr, "en/", SLEN("en/"));
+ ptr += SLEN("en/");
+ }
+
+ /* Add filename to URL */
+ memcpy(ptr, path, path_len);
+ ptr += path_len;
+
+ /* Terminate string */
+ *ptr = '\0';
+
+ nsurl_create(raw, &url);
+ free(raw);
+ }
+
+ return url;
+}
+
+
+/**
+ * Set colour option from wimp.
+ *
+ * \param opts The netsurf options.
+ * \param wimp wimp colour value
+ * \param option the netsurf option enum.
+ * \param def_colour The default colour value to use.
+ * \return NSERROR_OK on success or error code.
+ */
+static nserror
+set_colour_from_wimp(struct nsoption_s *opts,
+ wimp_colour wimp,
+ enum nsoption_e option,
+ colour def_colour)
+{
+ os_error *error;
+ os_PALETTE(20) palette;
+
+ error = xwimp_read_true_palette((os_palette *) &palette);
+ if (error != NULL) {
+ LOG("xwimp_read_palette: 0x%x: %s",
+ error->errnum, error->errmess);
+ } else {
+ /* entries are in B0G0R0LL */
+ def_colour = palette.entries[wimp] >> 8;
+ }
+
+ opts[option].value.c = def_colour;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Set option defaults for riscos frontend
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ *
+ * @todo The wimp_COLOUR_... values here map the colour definitions to
+ * parts of the RISC OS desktop palette. In places this is fairly
+ * arbitrary, and could probably do with re-checking.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
+{
+ /* Set defaults for absent option strings */
+ nsoption_setnull_charp(ca_bundle, strdup("NetSurf:Resources.ca-bundle"));
+ nsoption_setnull_charp(cookie_file, strdup("NetSurf:Cookies"));
+ nsoption_setnull_charp(cookie_jar, strdup(CHOICES_PREFIX "Cookies"));
+
+ if (nsoption_charp(ca_bundle) == NULL ||
+ nsoption_charp(cookie_file) == NULL ||
+ nsoption_charp(cookie_jar) == NULL) {
+ LOG("Failed initialising default options");
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* RISC OS platform does not generally benefit from disc cache
+ * so the default should be off.
+ */
+ nsoption_set_uint(disc_cache_size, 0);
+
+ /* set default system colours for riscos ui */
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_ActiveBorder, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_CREAM, NSOPTION_sys_colour_ActiveCaption, 0x00dddddd);
+ set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_AppWorkspace, 0x00eeeeee);
+ set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_Background, 0x00aa0000);/* \TODO -- Check */
+ set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_ButtonFace, 0x00aaaaaa);
+ set_colour_from_wimp(defaults, wimp_COLOUR_DARK_GREY, NSOPTION_sys_colour_ButtonHighlight, 0x00cccccc);/* \TODO -- Check */
+ set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ButtonShadow, 0x00bbbbbb);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_ButtonText, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_CaptionText, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_MID_LIGHT_GREY, NSOPTION_sys_colour_GrayText, 0x00777777);/* \TODO -- Check */
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_Highlight, 0x00ee0000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_HighlightText, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InactiveBorder, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_LIGHT_GREY, NSOPTION_sys_colour_InactiveCaption, 0x00ffffff);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InactiveCaptionText, 0x00cccccc);
+ set_colour_from_wimp(defaults, wimp_COLOUR_CREAM, NSOPTION_sys_colour_InfoBackground, 0x00aaaaaa);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_InfoText, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_Menu, 0x00aaaaaa);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_MenuText, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_LIGHT_GREY, NSOPTION_sys_colour_Scrollbar, 0x00aaaaaa);/* \TODO -- Check */
+ set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ThreeDDarkShadow, 0x00555555);
+ set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_ThreeDFace, 0x00dddddd);
+ set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_ThreeDHighlight, 0x00aaaaaa);
+ set_colour_from_wimp(defaults, wimp_COLOUR_WHITE, NSOPTION_sys_colour_ThreeDLightShadow, 0x00999999);
+ set_colour_from_wimp(defaults, wimp_COLOUR_MID_DARK_GREY, NSOPTION_sys_colour_ThreeDShadow, 0x00777777);
+ set_colour_from_wimp(defaults, wimp_COLOUR_VERY_LIGHT_GREY, NSOPTION_sys_colour_Window, 0x00aaaaaa);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_WindowFrame, 0x00000000);
+ set_colour_from_wimp(defaults, wimp_COLOUR_BLACK, NSOPTION_sys_colour_WindowText, 0x00000000);
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Create intermediate directories for Choices and User Data files
+ */
+static void ro_gui_create_dirs(void)
+{
+ char buf[256];
+ char *path;
+
+ /* Choices */
+ path = getenv("NetSurf$ChoicesSave");
+ if (!path)
+ die("Failed to find NetSurf Choices save path");
+
+ snprintf(buf, sizeof(buf), "%s", path);
+ netsurf_mkdir_all(buf);
+
+ /* URL */
+ snprintf(buf, sizeof(buf), "%s", nsoption_charp(url_save));
+ netsurf_mkdir_all(buf);
+
+ /* Hotlist */
+ snprintf(buf, sizeof(buf), "%s", nsoption_charp(hotlist_save));
+ netsurf_mkdir_all(buf);
+
+ /* Recent */
+ snprintf(buf, sizeof(buf), "%s", nsoption_charp(recent_save));
+ netsurf_mkdir_all(buf);
+
+ /* Theme */
+ snprintf(buf, sizeof(buf), "%s", nsoption_charp(theme_save));
+ netsurf_mkdir_all(buf);
+ /* and the final directory part (as theme_save is a directory) */
+ xosfile_create_dir(buf, 0);
+}
+
+
+/**
+ * Ensures the gui exits cleanly.
+ */
+static void ro_gui_cleanup(void)
+{
+ ro_gui_buffer_close();
+ xhourglass_off();
+ /* Uninstall NetSurf-specific fonts */
+ xos_cli("FontRemove NetSurf:Resources.Fonts.");
+}
+
+
+/**
+ * Handles a signal
+ */
+static void ro_gui_signal(int sig)
+{
+ static const os_error error = { 1, "NetSurf has detected a serious "
+ "error and must exit. Please submit a bug report, "
+ "attaching the browser log file." };
+ os_colour old_sand, old_glass;
+
+ ro_gui_cleanup();
+
+ xhourglass_on();
+ xhourglass_colours(0x0000ffff, 0x000000ff, &old_sand, &old_glass);
+ nsoption_dump(stderr, NULL);
+ /*rufl_dump_state();*/
+
+#ifndef __ELF__
+ /* save WimpSlot and DA to files if NetSurf$CoreDump exists */
+ int used;
+ xos_read_var_val_size("NetSurf$CoreDump", 0, 0, &used, 0, 0);
+ if (used) {
+ int curr_slot;
+ xwimp_slot_size(-1, -1, &curr_slot, 0, 0);
+ LOG("saving WimpSlot, size 0x%x", curr_slot);
+ xosfile_save("$.NetSurf_Slot", 0x8000, 0,
+ (byte *) 0x8000,
+ (byte *) 0x8000 + curr_slot);
+
+ if (__dynamic_num != -1) {
+ int size;
+ byte *base_address;
+ xosdynamicarea_read(__dynamic_num, &size,
+ &base_address, 0, 0, 0, 0, 0);
+ LOG("saving DA %i, base %p, size 0x%x", __dynamic_num, base_address, size);
+ xosfile_save("$.NetSurf_DA",
+ (bits) base_address, 0,
+ base_address,
+ base_address + size);
+ }
+ }
+#else
+ /* Save WimpSlot and UnixLib managed DAs when UnixEnv$coredump
+ * defines a coredump directory. */
+ const _kernel_oserror *err = __unixlib_write_coredump (NULL);
+ if (err != NULL)
+ LOG("Coredump failed: %s", err->errmess);
+#endif
+
+ xhourglass_colours(old_sand, old_glass, 0, 0);
+ xhourglass_off();
+
+ __write_backtrace(sig);
+
+ xwimp_report_error_by_category(&error,
+ wimp_ERROR_BOX_GIVEN_CATEGORY |
+ wimp_ERROR_BOX_CATEGORY_ERROR <<
+ wimp_ERROR_BOX_CATEGORY_SHIFT,
+ "NetSurf", "!netsurf",
+ (osspriteop_area *) 1, "Quit", 0);
+ xos_cli("Filer_Run <Wimp$ScrapDir>.WWW.NetSurf.Log");
+
+ _Exit(sig);
+}
+
+
+/**
+ * Read a "line" from an Acorn URI file.
+ *
+ * \param fp file pointer to read from
+ * \param b buffer for line, size 400 bytes
+ * \return true on success, false on EOF
+ */
+static bool ro_gui_uri_file_parse_line(FILE *fp, char *b)
+{
+ int c;
+ unsigned int i = 0;
+
+ c = getc(fp);
+ if (c == EOF)
+ return false;
+
+ /* skip comment lines */
+ while (c == '#') {
+ do { c = getc(fp); } while (c != EOF && 32 <= c);
+ if (c == EOF)
+ return false;
+ do { c = getc(fp); } while (c != EOF && c < 32);
+ if (c == EOF)
+ return false;
+ }
+
+ /* read "line" */
+ do {
+ if (i == 399)
+ return false;
+ b[i++] = c;
+ c = getc(fp);
+ } while (c != EOF && 32 <= c);
+
+ /* skip line ending control characters */
+ while (c != EOF && c < 32)
+ c = getc(fp);
+
+ if (c != EOF)
+ ungetc(c, fp);
+
+ b[i] = 0;
+ return true;
+}
+
+
+/**
+ * Parse an Acorn URI file.
+ *
+ * \param file_name file to read
+ * \param uri_title pointer to receive title data, or NULL for no data
+ * \return URL from file, or 0 on error and error reported
+ */
+static char *ro_gui_uri_file_parse(const char *file_name, char **uri_title)
+{
+ /* See the "Acorn URI Handler Functional Specification" for the
+ * definition of the URI file format. */
+ char line[400];
+ char *url = NULL;
+ FILE *fp;
+
+ *uri_title = NULL;
+ fp = fopen(file_name, "rb");
+ if (!fp) {
+ LOG("fopen(\"%s\", \"rb\"): %i: %s", file_name, errno, strerror(errno));
+ ro_warn_user("LoadError", strerror(errno));
+ return 0;
+ }
+
+ /* "URI" */
+ if (!ro_gui_uri_file_parse_line(fp, line) || strcmp(line, "URI") != 0)
+ goto uri_syntax_error;
+
+ /* version */
+ if (!ro_gui_uri_file_parse_line(fp, line) ||
+ strspn(line, "0123456789") != strlen(line))
+ goto uri_syntax_error;
+
+ /* URI */
+ if (!ro_gui_uri_file_parse_line(fp, line))
+ goto uri_syntax_error;
+
+ url = strdup(line);
+ if (!url) {
+ ro_warn_user("NoMemory", 0);
+ fclose(fp);
+ return 0;
+ }
+
+ /* title */
+ if (!ro_gui_uri_file_parse_line(fp, line))
+ goto uri_free;
+ if (uri_title && line[0] && ((line[0] != '*') || line[1])) {
+ *uri_title = strdup(line);
+ if (!*uri_title) /* non-fatal */
+ ro_warn_user("NoMemory", 0);
+ }
+ fclose(fp);
+
+ return url;
+
+uri_free:
+ free(url);
+
+uri_syntax_error:
+ fclose(fp);
+ ro_warn_user("URIError", 0);
+ return 0;
+}
+
+
+/**
+ * Parse an ANT URL file.
+ *
+ * \param file_name file to read
+ * \return URL from file, or 0 on error and error reported
+ */
+static char *ro_gui_url_file_parse(const char *file_name)
+{
+ char line[400];
+ char *url;
+ FILE *fp;
+
+ fp = fopen(file_name, "r");
+ if (!fp) {
+ LOG("fopen(\"%s\", \"r\"): %i: %s", file_name, errno, strerror(errno));
+ ro_warn_user("LoadError", strerror(errno));
+ return 0;
+ }
+
+ if (!fgets(line, sizeof line, fp)) {
+ if (ferror(fp)) {
+ LOG("fgets: %i: %s", errno, strerror(errno));
+ ro_warn_user("LoadError", strerror(errno));
+ } else
+ ro_warn_user("LoadError", messages_get("EmptyError"));
+ fclose(fp);
+ return 0;
+ }
+
+ fclose(fp);
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ url = strdup(line);
+ if (!url) {
+ ro_warn_user("NoMemory", 0);
+ return 0;
+ }
+
+ return url;
+}
+
+
+/**
+ * Parse an IEURL file.
+ *
+ * \param file_name file to read
+ * \return URL from file, or 0 on error and error reported
+ */
+static char *ro_gui_ieurl_file_parse(const char *file_name)
+{
+ char line[400];
+ char *url = 0;
+ FILE *fp;
+
+ fp = fopen(file_name, "r");
+ if (!fp) {
+ LOG("fopen(\"%s\", \"r\"): %i: %s", file_name, errno, strerror(errno));
+ ro_warn_user("LoadError", strerror(errno));
+ return 0;
+ }
+
+ while (fgets(line, sizeof line, fp)) {
+ if (strncmp(line, "URL=", 4) == 0) {
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+ url = strdup(line + 4);
+ if (!url) {
+ fclose(fp);
+ ro_warn_user("NoMemory", 0);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (ferror(fp)) {
+ LOG("fgets: %i: %s", errno, strerror(errno));
+ ro_warn_user("LoadError", strerror(errno));
+ fclose(fp);
+ return 0;
+ }
+
+ fclose(fp);
+
+ if (!url)
+ ro_warn_user("URIError", 0);
+
+ return url;
+}
+
+
+/**
+ * Handle Message_DataOpen (double-click on file in the Filer).
+ *
+ * \param message The wimp message to open.
+ */
+static void ro_msg_dataopen(wimp_message *message)
+{
+ int file_type = message->data.data_xfer.file_type;
+ char *url = 0;
+ os_error *oserror;
+ nsurl *urlns;
+ nserror error;
+ size_t len;
+
+ switch (file_type) {
+ case 0xb28: /* ANT URL file */
+ url = ro_gui_url_file_parse(message->data.data_xfer.file_name);
+ error = nsurl_create(url, &urlns);
+ free(url);
+ break;
+
+ case 0xfaf: /* HTML file */
+ error = netsurf_path_to_nsurl(message->data.data_xfer.file_name,
+ &urlns);
+ break;
+
+ case 0x1ba: /* IEURL file */
+ url = ro_gui_ieurl_file_parse(message->
+ data.data_xfer.file_name);
+ error = nsurl_create(url, &urlns);
+ free(url);
+ break;
+
+ case 0x2000: /* application */
+ len = strlen(message->data.data_xfer.file_name);
+ if (len < 9 || strcmp(".!NetSurf",
+ message->data.data_xfer.file_name + len - 9))
+ return;
+
+ if (nsoption_charp(homepage_url) &&
+ nsoption_charp(homepage_url)[0]) {
+ error = nsurl_create(nsoption_charp(homepage_url),
+ &urlns);
+ } else {
+ error = nsurl_create(NETSURF_HOMEPAGE, &urlns);
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ /* send DataLoadAck */
+ message->action = message_DATA_LOAD_ACK;
+ message->your_ref = message->my_ref;
+ oserror = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender);
+ if (oserror) {
+ LOG("xwimp_send_message: 0x%x: %s", oserror->errnum, oserror->errmess);
+ ro_warn_user("WimpError", oserror->errmess);
+ return;
+ }
+
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ return;
+ }
+
+ /* create a new window with the file */
+ error = browser_window_create(BW_CREATE_HISTORY,
+ urlns,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(urlns);
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ }
+}
+
+
+/**
+ * Handle Message_DataLoad (file dragged in).
+ */
+static void ro_msg_dataload(wimp_message *message)
+{
+ int file_type = message->data.data_xfer.file_type;
+ char *urltxt = NULL;
+ char *title = NULL;
+ struct gui_window *g;
+ os_error *oserror;
+ nsurl *url;
+ nserror error;
+
+ g = ro_gui_window_lookup(message->data.data_xfer.w);
+ if (g) {
+ if (ro_gui_window_dataload(g, message))
+ return;
+ }
+ else {
+ g = ro_gui_toolbar_lookup(message->data.data_xfer.w);
+ if (g && ro_gui_toolbar_dataload(g, message))
+ return;
+ }
+
+ switch (file_type) {
+ case FILETYPE_ACORN_URI:
+ urltxt = ro_gui_uri_file_parse(message->data.data_xfer.file_name,
+ &title);
+ error = nsurl_create(urltxt, &url);
+ free(urltxt);
+ break;
+
+ case FILETYPE_ANT_URL:
+ urltxt = ro_gui_url_file_parse(message->data.data_xfer.file_name);
+ error = nsurl_create(urltxt, &url);
+ free(urltxt);
+ break;
+
+ case FILETYPE_IEURL:
+ urltxt = ro_gui_ieurl_file_parse(message->data.data_xfer.file_name);
+ error = nsurl_create(urltxt, &url);
+ free(urltxt);
+ break;
+
+ case FILETYPE_HTML:
+ case FILETYPE_JNG:
+ case FILETYPE_CSS:
+ case FILETYPE_MNG:
+ case FILETYPE_GIF:
+ case FILETYPE_BMP:
+ case FILETYPE_ICO:
+ case osfile_TYPE_DRAW:
+ case FILETYPE_PNG:
+ case FILETYPE_JPEG:
+ case osfile_TYPE_SPRITE:
+ case osfile_TYPE_TEXT:
+ case FILETYPE_ARTWORKS:
+ case FILETYPE_SVG:
+ /* display the actual file */
+ error = netsurf_path_to_nsurl(message->data.data_xfer.file_name, &url);
+ break;
+
+ default:
+ return;
+ }
+
+ /* report error to user */
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ return;
+ }
+
+
+ if (g) {
+ error = browser_window_navigate(g->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ } else {
+ error = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ }
+ nsurl_unref(url);
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ }
+
+
+ /* send DataLoadAck */
+ message->action = message_DATA_LOAD_ACK;
+ message->your_ref = message->my_ref;
+ oserror = xwimp_send_message(wimp_USER_MESSAGE, message,
+ message->sender);
+ if (oserror) {
+ LOG("xwimp_send_message: 0x%x: %s", oserror->errnum, oserror->errmess);
+ ro_warn_user("WimpError", oserror->errmess);
+ return;
+ }
+
+}
+
+
+/**
+ * Ensure that the filename in a data transfer message is NULL terminated
+ * (some applications, especially BASIC programs use CR)
+ *
+ * \param message message to be corrected
+ */
+static void ro_msg_terminate_filename(wimp_full_message_data_xfer *message)
+{
+ const char *ep = (char*)message + message->size;
+ char *p = message->file_name;
+
+ if ((size_t)message->size >= sizeof(*message))
+ ep = (char*)message + sizeof(*message) - 1;
+
+ while (p < ep && *p >= ' ') p++;
+ *p = '\0';
+}
+
+
+/**
+ * Handle Message_DataSave
+ */
+static 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);
+
+ if (ro_gui_selection_prepare_paste_datasave(dataxfer))
+ return;
+
+ switch (dataxfer->file_type) {
+ case FILETYPE_ACORN_URI:
+ case FILETYPE_ANT_URL:
+ case FILETYPE_IEURL:
+ case FILETYPE_HTML:
+ case FILETYPE_JNG:
+ case FILETYPE_CSS:
+ case FILETYPE_MNG:
+ case FILETYPE_GIF:
+ case FILETYPE_BMP:
+ case FILETYPE_ICO:
+ case osfile_TYPE_DRAW:
+ case FILETYPE_PNG:
+ case FILETYPE_JPEG:
+ case osfile_TYPE_SPRITE:
+ case osfile_TYPE_TEXT:
+ case FILETYPE_ARTWORKS:
+ case FILETYPE_SVG: {
+ os_error *error;
+
+ 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, "<Wimp$Scrap>", 13);
+
+ error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)dataxfer, message->sender);
+ if (error) {
+ LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+ break;
+ }
+}
+
+
+/**
+ * Handle Message_DataSaveAck.
+ */
+static void ro_msg_datasave_ack(wimp_message *message)
+{
+ ro_msg_terminate_filename((wimp_full_message_data_xfer*)message);
+
+ if (ro_print_ack(message))
+ return;
+
+ switch (gui_current_drag_type) {
+ case GUI_DRAG_DOWNLOAD_SAVE:
+ ro_gui_download_datasave_ack(message);
+ break;
+
+ case GUI_DRAG_SAVE:
+ ro_gui_save_datasave_ack(message);
+ gui_current_drag_type = GUI_DRAG_NONE;
+ break;
+
+ default:
+ break;
+ }
+
+ gui_current_drag_type = GUI_DRAG_NONE;
+}
+
+
+/**
+ * Handle PreQuit message
+ *
+ * \param message PreQuit message from Wimp
+ */
+static void ro_msg_prequit(wimp_message *message)
+{
+ if (!ro_gui_prequit()) {
+ os_error *error;
+
+ /* we're objecting to the close down */
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE,
+ message, message->sender);
+ if (error) {
+ LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+}
+
+
+/**
+ * Handle SaveDesktop message.
+ *
+ * \param message SaveDesktop message from Wimp.
+ */
+static void ro_msg_save_desktop(wimp_message *message)
+{
+ os_error *error;
+
+ error = xosgbpb_writew(message->data.save_desktopw.file,
+ (const byte*)"Run ", 4, NULL);
+ if (!error) {
+ error = xosgbpb_writew(message->data.save_desktopw.file,
+ (const byte*)NETSURF_DIR, strlen(NETSURF_DIR), NULL);
+ if (!error)
+ error = xos_bputw('\n', message->data.save_desktopw.file);
+ }
+
+ if (error) {
+ LOG("xosgbpb_writew/xos_bputw: 0x%x:%s", error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+
+ /* we must cancel the save by acknowledging the message */
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE,
+ message, message->sender);
+ if (error) {
+ LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+}
+
+
+/**
+ * Handle WindowInfo message (part of the iconising protocol)
+ *
+ * \param message WindowInfo message from the Iconiser
+ */
+static void ro_msg_window_info(wimp_message *message)
+{
+ wimp_full_message_window_info *wi;
+ struct gui_window *g;
+
+ /* allow the user to turn off thumbnail icons */
+ if (!nsoption_bool(thumbnail_iconise))
+ return;
+
+ wi = (wimp_full_message_window_info*)message;
+ g = ro_gui_window_lookup(wi->w);
+
+ /* ic_<task name> will suffice for our other windows */
+ if (g) {
+ ro_gui_window_iconise(g, wi);
+ ro_gui_dialog_close_persistent(wi->w);
+ }
+}
+
+
+/**
+ * Get screen properties following a mode change.
+ */
+static void ro_gui_get_screen_properties(void)
+{
+ static const ns_os_vdu_var_list vars = {
+ os_MODEVAR_XWIND_LIMIT,
+ {
+ os_MODEVAR_YWIND_LIMIT,
+ os_MODEVAR_XEIG_FACTOR,
+ os_MODEVAR_YEIG_FACTOR,
+ os_VDUVAR_END_LIST
+ }
+ };
+ os_error *error;
+ int vals[4];
+
+ error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), vals);
+ if (error) {
+ LOG("xos_read_vdu_variables: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ return;
+ }
+ screen_info.width = (vals[0] + 1) << vals[2];
+ screen_info.height = (vals[1] + 1) << vals[3];
+}
+
+
+/**
+ * Warn the user if Inet$Resolvers is not set.
+ */
+static void ro_gui_check_resolvers(void)
+{
+ char *resolvers;
+ resolvers = getenv("Inet$Resolvers");
+ if (resolvers && resolvers[0]) {
+ LOG("Inet$Resolvers '%s'", resolvers);
+ } else {
+ LOG("Inet$Resolvers not set or empty");
+ ro_warn_user("Resolvers", 0);
+ }
+}
+
+
+/**
+ * Initialise the RISC OS specific GUI.
+ *
+ * \param argc The number of command line arguments.
+ * \param argv The string vector of command line arguments.
+ */
+static nserror gui_init(int argc, char** argv)
+{
+ struct {
+ void (*sigabrt)(int);
+ void (*sigfpe)(int);
+ void (*sigill)(int);
+ void (*sigint)(int);
+ void (*sigsegv)(int);
+ void (*sigterm)(int);
+ void (*sigoserror)(int);
+ } prev_sigs;
+ char path[40];
+ os_error *error;
+ int length;
+ char *nsdir_temp;
+ byte *base;
+ nsurl *url;
+ nserror ret;
+ bool open_window;
+
+ /* re-enable all FPU exceptions/traps except inexact operations,
+ * which we're not interested in, and underflow which is incorrectly
+ * raised when converting an exact value of 0 from double-precision
+ * to single-precision on FPEmulator v4.09-4.11 (MVFD F0,#0:MVFS F0,F0)
+ * - UnixLib disables all FP exceptions by default */
+
+ _FPU_SETCW(_FPU_IEEE & ~(_FPU_MASK_PM | _FPU_MASK_UM));
+
+ xhourglass_start(1);
+
+ /* read OS version for code that adapts to conform to the OS
+ * (remember that it's preferable to check for specific features
+ * being present) */
+ xos_byte(osbyte_IN_KEY, 0, 0xff, &os_version, NULL);
+
+ /* the first release version of the A9home OS is incapable of
+ plotting patterned lines (presumably a fault in the hw acceleration) */
+ if (!xosmodule_lookup("VideoHWSMI", NULL, NULL, &base, NULL, NULL)) {
+#if 0 // this fault still hasn't been fixed, so disable patterned lines for all versions until it has
+ const char *help = (char*)base + ((int*)base)[5];
+ while (*help > 9) help++;
+ while (*help == 9) help++;
+ if (!memcmp(help, "0.55", 4))
+#endif
+ ro_plot_patterned_lines = false;
+ }
+
+ /* Create our choices directories */
+ ro_gui_create_dirs();
+
+ /* Register exit and signal handlers */
+ atexit(ro_gui_cleanup);
+ prev_sigs.sigabrt = signal(SIGABRT, ro_gui_signal);
+ prev_sigs.sigfpe = signal(SIGFPE, ro_gui_signal);
+ prev_sigs.sigill = signal(SIGILL, ro_gui_signal);
+ prev_sigs.sigint = signal(SIGINT, ro_gui_signal);
+ prev_sigs.sigsegv = signal(SIGSEGV, ro_gui_signal);
+ prev_sigs.sigterm = signal(SIGTERM, ro_gui_signal);
+ prev_sigs.sigoserror = signal(SIGOSERROR, ro_gui_signal);
+
+ if (prev_sigs.sigabrt == SIG_ERR || prev_sigs.sigfpe == SIG_ERR ||
+ prev_sigs.sigill == SIG_ERR ||
+ prev_sigs.sigint == SIG_ERR ||
+ prev_sigs.sigsegv == SIG_ERR ||
+ prev_sigs.sigterm == SIG_ERR ||
+ prev_sigs.sigoserror == SIG_ERR)
+ die("Failed registering signal handlers");
+
+ /* Load in UI sprites */
+ gui_sprites = ro_gui_load_sprite_file("NetSurf:Resources.Sprites");
+ if (!gui_sprites)
+ die("Unable to load Sprites.");
+
+ /* Find NetSurf directory */
+ nsdir_temp = getenv("NetSurf$Dir");
+ if (!nsdir_temp)
+ die("Failed to locate NetSurf directory");
+ NETSURF_DIR = strdup(nsdir_temp);
+ if (!NETSURF_DIR)
+ die("Failed duplicating NetSurf directory string");
+
+ /* Initialise filename allocator */
+ filename_initialise();
+
+ /* Initialise save complete functionality */
+ save_complete_init();
+
+ /* Load in visited URLs and Cookies */
+ urldb_load(nsoption_charp(url_path));
+ urldb_load_cookies(nsoption_charp(cookie_file));
+
+ /* Initialise with the wimp */
+ error = xwimp_initialise(wimp_VERSION_RO38, task_name,
+ PTR_WIMP_MESSAGE_LIST(&task_messages), 0,
+ &task_handle);
+ if (error) {
+ LOG("xwimp_initialise: 0x%x: %s", error->errnum, error->errmess);
+ die(error->errmess);
+ }
+ /* Register message handlers */
+ ro_message_register_route(message_HELP_REQUEST,
+ ro_gui_interactive_help_request);
+ ro_message_register_route(message_DATA_OPEN,
+ ro_msg_dataopen);
+ ro_message_register_route(message_DATA_SAVE,
+ ro_msg_datasave);
+ ro_message_register_route(message_DATA_SAVE_ACK,
+ ro_msg_datasave_ack);
+ ro_message_register_route(message_PRE_QUIT,
+ 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);
+ ro_message_register_route(message_WINDOW_INFO,
+ ro_msg_window_info);
+
+ /* Initialise the font subsystem */
+ nsfont_init();
+
+ /* Initialise global information */
+ ro_gui_get_screen_properties();
+ ro_gui_wimp_get_desktop_font();
+
+ /* Issue a *Desktop to poke AcornURI into life */
+ if (getenv("NetSurf$Start_URI_Handler"))
+ xwimp_start_task("Desktop", 0);
+
+ /* Open the templates */
+ if ((length = snprintf(path, sizeof(path),
+ "NetSurf:Resources.%s.Templates",
+ nsoption_charp(language))) < 0 || length >= (int)sizeof(path))
+ die("Failed to locate Templates resource.");
+ error = xwimp_open_template(path);
+ if (error) {
+ LOG("xwimp_open_template failed: 0x%x: %s", error->errnum, error->errmess);
+ die(error->errmess);
+ }
+
+ ret = treeview_init(12);
+ if (ret != NSERROR_OK) {
+ die("Failed to initialise treeview");
+ }
+
+ /* Initialise themes before dialogs */
+ ro_gui_theme_initialise();
+
+ /* Initialise dialog windows (must be after UI sprites are loaded) */
+ ro_gui_dialog_init();
+
+ /* Initialise download window */
+ ro_gui_download_init();
+
+ /* Initialise menus */
+ ro_gui_menu_init();
+
+ /* Initialise query windows */
+ ro_gui_query_init();
+
+ /* Initialise the history subsystem */
+ ro_gui_history_init();
+
+ /* Initialise toolbars */
+ ro_toolbar_init();
+
+ /* Initialise url bar module */
+ ro_gui_url_bar_init();
+
+ /* Initialise browser windows */
+ ro_gui_window_initialise();
+
+ /* Done with the templates file */
+ wimp_close_template();
+
+ /* Create Iconbar icon and menus */
+ ro_gui_iconbar_initialise();
+
+ /* Finally, check Inet$Resolvers for sanity */
+ ro_gui_check_resolvers();
+
+ /* certificate verification window */
+ ro_gui_cert_postinitialise();
+
+ /* hotlist window */
+ ro_gui_hotlist_postinitialise();
+
+ /* global history window */
+ ro_gui_global_history_postinitialise();
+
+ /* cookies window */
+ ro_gui_cookies_postinitialise();
+
+ open_window = nsoption_bool(open_browser_at_startup);
+
+ /* parse command-line arguments */
+ if (argc == 2) {
+ LOG("parameters: '%s'", argv[1]);
+ /* this is needed for launching URI files */
+ if (strcasecmp(argv[1], "-nowin") == 0) {
+ return NSERROR_OK;
+ }
+ ret = nsurl_create(NETSURF_HOMEPAGE, &url);
+ }
+ else if (argc == 3) {
+ LOG("parameters: '%s' '%s'", argv[1], argv[2]);
+ open_window = true;
+
+ /* HTML files */
+ if (strcasecmp(argv[1], "-html") == 0) {
+ ret = netsurf_path_to_nsurl(argv[2], &url);
+ }
+ /* URL files */
+ else if (strcasecmp(argv[1], "-urlf") == 0) {
+ char *urlf = ro_gui_url_file_parse(argv[2]);
+ if (!urlf) {
+ LOG("allocation failed");
+ die("Insufficient memory for URL");
+ }
+ ret = nsurl_create(urlf, &url);
+ free(urlf);
+ }
+ /* ANT URL Load */
+ else if (strcasecmp(argv[1], "-url") == 0) {
+ ret = nsurl_create(argv[2], &url);
+ }
+ /* Unknown => exit here. */
+ else {
+ LOG("Unknown parameters: '%s' '%s'", argv[1], argv[2]);
+ return NSERROR_BAD_PARAMETER;
+ }
+ }
+ /* get user's homepage (if configured) */
+ else if (nsoption_charp(homepage_url) &&
+ nsoption_charp(homepage_url)[0]) {
+ ret = nsurl_create(nsoption_charp(homepage_url), &url);
+ }
+ /* default homepage */
+ else {
+ ret = nsurl_create(NETSURF_HOMEPAGE, &url);
+ }
+
+ /* check for url creation error */
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ if (open_window) {
+ ret = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ }
+ nsurl_unref(url);
+
+ return ret;
+}
+
+
+/**
+ * Determine the default language to use.
+ *
+ * RISC OS has no standard way of determining which language the user prefers.
+ * We have to guess from the 'Country' setting.
+ */
+const char *ro_gui_default_language(void)
+{
+ char path[40];
+ const char *lang;
+ int country;
+ os_error *error;
+
+ /* choose a language from the configured country number */
+ error = xosbyte_read(osbyte_VAR_COUNTRY_NUMBER, &country);
+ if (error) {
+ LOG("xosbyte_read failed: 0x%x: %s", error->errnum, error->errmess);
+ country = 1;
+ }
+ switch (country) {
+ case 7: /* Germany */
+ case 30: /* Austria */
+ case 35: /* Switzerland (70% German-speaking) */
+ lang = "de";
+ break;
+ case 6: /* France */
+ case 18: /* Canada2 (French Canada?) */
+ lang = "fr";
+ break;
+ case 34: /* Netherlands */
+ lang = "nl";
+ break;
+ default:
+ lang = "en";
+ break;
+ }
+ sprintf(path, "NetSurf:Resources.%s", lang);
+ if (is_dir(path))
+ return lang;
+ return "en";
+}
+
+
+/**
+ * Create a nsurl from a RISC OS pathname.
+ *
+ * Perform the necessary operations on a path to generate a nsurl.
+ *
+ * @param[in] path The RISC OS pathname to convert.
+ * @param[out] url_out pointer to recive the nsurl, The returned url must be
+ * unreferenced by the caller.
+ * @return NSERROR_OK and the url is placed in \a url or error code on faliure.
+ */
+static nserror ro_path_to_nsurl(const char *path, struct nsurl **url_out)
+{
+ int spare;
+ char *canonical_path; /* canonicalised RISC OS path */
+ char *unix_path; /* unix path */
+ char *escurl;
+ os_error *error;
+ nserror ret;
+ int urllen;
+ char *url; /* resulting url */
+
+ /* calculate the canonical risc os path */
+ error = xosfscontrol_canonicalise_path(path, 0, 0, 0, 0, &spare);
+ if (error) {
+ LOG("xosfscontrol_canonicalise_path failed: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PathToURL", error->errmess);
+ return NSERROR_NOT_FOUND;
+ }
+
+ canonical_path = malloc(1 - spare);
+ if (canonical_path == NULL) {
+ free(canonical_path);
+ return NSERROR_NOMEM;
+ }
+
+ error = xosfscontrol_canonicalise_path(path, canonical_path, 0, 0, 1 - spare, 0);
+ if (error) {
+ LOG("xosfscontrol_canonicalise_path failed: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PathToURL", error->errmess);
+ free(canonical_path);
+ return NSERROR_NOT_FOUND;
+ }
+
+ /* create a unix path from the cananocal risc os one */
+ unix_path = __unixify(canonical_path, __RISCOSIFY_NO_REVERSE_SUFFIX, NULL, 0, 0);
+
+ if (unix_path == NULL) {
+ LOG("__unixify failed: %s", canonical_path);
+ free(canonical_path);
+ return NSERROR_BAD_PARAMETER;
+ }
+ free(canonical_path);
+
+ /* convert the unix path into a url */
+ urllen = strlen(unix_path) + FILE_SCHEME_PREFIX_LEN + 1;
+ url = malloc(urllen);
+ if (url == NULL) {
+ LOG("Unable to allocate url");
+ free(unix_path);
+ return NSERROR_NOMEM;
+ }
+
+ if (*unix_path == '/') {
+ snprintf(url, urllen, "%s%s", FILE_SCHEME_PREFIX, unix_path + 1);
+ } else {
+ snprintf(url, urllen, "%s%s", FILE_SCHEME_PREFIX, unix_path);
+ }
+ free(unix_path);
+
+ /* We don't want '/' to be escaped. */
+ ret = url_escape(url, FILE_SCHEME_PREFIX_LEN, false, "/", &escurl);
+ free(url);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ ret = nsurl_create(escurl, url_out);
+ free(escurl);
+
+ return ret;
+}
+
+
+/**
+ * Create a path from a nsurl using posix file handling.
+ *
+ * @param[in] url The url to encode.
+ * @param[out] path_out A string containing the result path which should
+ * be freed by the caller.
+ * @return NSERROR_OK and the path is written to \a path or error code
+ * on faliure.
+ */
+static nserror ro_nsurl_to_path(struct nsurl *url, char **path_out)
+{
+ lwc_string *urlpath;
+ char *unpath;
+ char *path;
+ bool match;
+ lwc_string *scheme;
+ nserror res;
+ char *r;
+
+ if ((url == NULL) || (path_out == NULL)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
+ &match) != lwc_error_ok)
+ {
+ return NSERROR_BAD_PARAMETER;
+ }
+ lwc_string_unref(scheme);
+ if (match == false) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ urlpath = nsurl_get_component(url, NSURL_PATH);
+ if (urlpath == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ res = url_unescape(lwc_string_data(urlpath), &unpath);
+ lwc_string_unref(urlpath);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* RISC OS path should not be more than 100 characters longer */
+ path = malloc(strlen(unpath) + 100);
+ if (path == NULL) {
+ free(unpath);
+ return NSERROR_NOMEM;
+ }
+
+ r = __riscosify(unpath, 0, __RISCOSIFY_NO_SUFFIX,
+ path, strlen(unpath) + 100, 0);
+ free(unpath);
+ if (r == NULL) {
+ free(path);
+ return NSERROR_NOMEM;
+ }
+
+ *path_out = path;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Ensures output logging stream is correctly configured.
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
+
+ return true;
+}
+
+
+/**
+ * Close down the gui (RISC OS).
+ */
+static void gui_quit(void)
+{
+ urldb_save_cookies(nsoption_charp(cookie_jar));
+ urldb_save(nsoption_charp(url_save));
+ ro_gui_window_quit();
+ ro_gui_global_history_destroy();
+ ro_gui_hotlist_destroy();
+ ro_gui_cookies_destroy();
+ ro_gui_saveas_quit();
+ ro_gui_url_bar_fini();
+ rufl_quit();
+ free(gui_sprites);
+ xwimp_close_down(task_handle);
+ xhourglass_off();
+}
+
+
+/**
+ * Handle Close_Window_Request events.
+ */
+static void ro_gui_close_window_request(wimp_close *close)
+{
+ if (ro_gui_alt_pressed())
+ ro_gui_window_close_all();
+ else {
+ if (ro_gui_wimp_event_close_window(close->w))
+ return;
+ ro_gui_dialog_close(close->w);
+ }
+}
+
+
+/**
+ * Handle key press paste callback.
+ */
+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);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+
+ free(key);
+}
+
+
+/**
+ * Handle gui keypress.
+ */
+static void ro_gui_keypress(wimp_key *key)
+{
+ if (key->c == wimp_KEY_ESCAPE &&
+ (gui_current_drag_type == GUI_DRAG_SAVE ||
+ gui_current_drag_type == GUI_DRAG_DOWNLOAD_SAVE)) {
+
+ /* Allow Escape key to be used for cancelling a drag
+ * save (easier than finding somewhere safe to abort
+ * the drag)
+ */
+ ro_gui_drag_box_cancel();
+ gui_current_drag_type = GUI_DRAG_NONE;
+ } 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", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+}
+
+
+/**
+ * Handle the three User_Message events.
+ */
+static void ro_gui_user_message(wimp_event_no event, wimp_message *message)
+{
+ /* attempt automatic routing */
+ if (ro_message_handle_message(event, message))
+ return;
+
+ switch (message->action) {
+ case message_DATA_LOAD:
+ ro_msg_terminate_filename((wimp_full_message_data_xfer*)message);
+
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) {
+ if (ro_print_current_window)
+ ro_print_dataload_bounce(message);
+ } 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:
+ if (ro_print_current_window)
+ ro_print_cleanup();
+ break;
+
+ case message_MENU_WARNING:
+ ro_gui_menu_warning((wimp_message_menu_warning *)
+ &message->data);
+ break;
+
+ case message_MENUS_DELETED:
+ ro_gui_menu_message_deleted((wimp_message_menus_deleted *)
+ &message->data);
+ break;
+
+ case message_CLAIM_ENTITY:
+ ro_gui_selection_claim_entity((wimp_full_message_claim_entity*)message);
+ break;
+
+ case message_DATA_REQUEST:
+ ro_gui_selection_data_request((wimp_full_message_data_request*)message);
+ break;
+
+ case message_MODE_CHANGE:
+ ro_gui_get_screen_properties();
+ rufl_invalidate_cache();
+ break;
+
+ case message_PALETTE_CHANGE:
+ break;
+
+ case message_FONT_CHANGED:
+ ro_gui_wimp_get_desktop_font();
+ break;
+
+ case message_URI_PROCESS:
+ if (event != wimp_USER_MESSAGE_ACKNOWLEDGE)
+ ro_uri_message_received(message);
+ break;
+ case message_URI_RETURN_RESULT:
+ ro_uri_bounce(message);
+ break;
+ case message_INET_SUITE_OPEN_URL:
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) {
+ ro_url_bounce(message);
+ }
+ else {
+ ro_url_message_received(message);
+ }
+ break;
+#ifdef WITH_PLUGIN
+ case message_PLUG_IN_OPENING:
+ plugin_opening(message);
+ break;
+ case message_PLUG_IN_CLOSED:
+ plugin_closed(message);
+ break;
+ case message_PLUG_IN_RESHAPE_REQUEST:
+ plugin_reshape_request(message);
+ break;
+ case message_PLUG_IN_FOCUS:
+ break;
+ case message_PLUG_IN_URL_ACCESS:
+ plugin_url_access(message);
+ break;
+ case message_PLUG_IN_STATUS:
+ plugin_status(message);
+ break;
+ case message_PLUG_IN_BUSY:
+ break;
+ case message_PLUG_IN_STREAM_NEW:
+ plugin_stream_new(message);
+ break;
+ case message_PLUG_IN_STREAM_WRITE:
+ break;
+ case message_PLUG_IN_STREAM_WRITTEN:
+ plugin_stream_written(message);
+ break;
+ case message_PLUG_IN_STREAM_DESTROY:
+ break;
+ case message_PLUG_IN_OPEN:
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE)
+ plugin_open_msg(message);
+ break;
+ case message_PLUG_IN_CLOSE:
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE)
+ plugin_close_msg(message);
+ break;
+ case message_PLUG_IN_RESHAPE:
+ case message_PLUG_IN_STREAM_AS_FILE:
+ case message_PLUG_IN_NOTIFY:
+ case message_PLUG_IN_ABORT:
+ case message_PLUG_IN_ACTION:
+ break;
+#endif
+ case message_PRINT_SAVE:
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE)
+ ro_print_save_bounce(message);
+ break;
+ case message_PRINT_ERROR:
+ ro_print_error(message);
+ break;
+ case message_PRINT_TYPE_ODD:
+ ro_print_type_odd(message);
+ break;
+ case message_HOTLIST_CHANGED:
+ ro_gui_hotlist_add_cleanup();
+ break;
+ case message_QUIT:
+ riscos_done = true;
+ break;
+ }
+}
+
+
+/**
+ * Process a Wimp_Poll event.
+ *
+ * \param event wimp event number
+ * \param block parameter block
+ */
+static void ro_gui_handle_event(wimp_event_no event, wimp_block *block)
+{
+ switch (event) {
+ case wimp_NULL_REASON_CODE:
+ ro_gui_throb();
+ ro_mouse_poll();
+ break;
+
+ case wimp_REDRAW_WINDOW_REQUEST:
+ ro_gui_wimp_event_redraw_window(&block->redraw);
+ break;
+
+ case wimp_OPEN_WINDOW_REQUEST:
+ ro_gui_open_window_request(&block->open);
+ break;
+
+ case wimp_CLOSE_WINDOW_REQUEST:
+ ro_gui_close_window_request(&block->close);
+ break;
+
+ case wimp_POINTER_LEAVING_WINDOW:
+ ro_mouse_pointer_leaving_window(&block->leaving);
+ break;
+
+ case wimp_POINTER_ENTERING_WINDOW:
+ ro_gui_wimp_event_pointer_entering_window(&block->entering);
+ break;
+
+ case wimp_MOUSE_CLICK:
+ ro_gui_wimp_event_mouse_click(&block->pointer);
+ break;
+
+ case wimp_USER_DRAG_BOX:
+ ro_mouse_drag_end(&block->dragged);
+ break;
+
+ case wimp_KEY_PRESSED:
+ ro_gui_keypress(&(block->key));
+ break;
+
+ case wimp_MENU_SELECTION:
+ ro_gui_menu_selection(&(block->selection));
+ break;
+
+ /* Scroll requests fall back to a generic handler because we
+ * might get these events for any window from a scroll-wheel.
+ */
+
+ case wimp_SCROLL_REQUEST:
+ if (!ro_gui_wimp_event_scroll_window(&(block->scroll)))
+ ro_gui_scroll(&(block->scroll));
+ break;
+
+ case wimp_USER_MESSAGE:
+ case wimp_USER_MESSAGE_RECORDED:
+ case wimp_USER_MESSAGE_ACKNOWLEDGE:
+ ro_gui_user_message(event, &(block->message));
+ break;
+ }
+}
+
+
+/**
+ * Poll the RISC OS wimp for events.
+ */
+static void riscos_poll(void)
+{
+ wimp_event_no event;
+ wimp_block block;
+ const wimp_poll_flags mask = wimp_MASK_LOSE | wimp_MASK_GAIN | wimp_SAVE_FP;
+ os_t track_poll_offset;
+
+ /* Poll wimp. */
+ xhourglass_off();
+ track_poll_offset = ro_mouse_poll_interval();
+ if (sched_active || (track_poll_offset > 0)) {
+ os_t t = os_read_monotonic_time();
+
+ if (track_poll_offset > 0) {
+ t += track_poll_offset;
+ } else {
+ t += 10;
+ }
+
+ if (sched_active && (sched_time - t) < 0) {
+ t = sched_time;
+ }
+
+ event = wimp_poll_idle(mask, &block, t, 0);
+ } else {
+ event = wimp_poll(wimp_MASK_NULL | mask, &block, 0);
+ }
+
+ xhourglass_on();
+ gui_last_poll = clock();
+ ro_gui_handle_event(event, &block);
+
+ /* Only run scheduled callbacks on a null poll
+ * We cannot do this in the null event handler, as that may be called
+ * from gui_multitask(). Scheduled callbacks must only be run from the
+ * top-level.
+ */
+ if (event == wimp_NULL_REASON_CODE) {
+ schedule_run();
+ }
+
+ ro_gui_window_update_boxes();
+}
+
+
+/**
+ * Handle Open_Window_Request events.
+ */
+void ro_gui_open_window_request(wimp_open *open)
+{
+ os_error *error;
+
+ if (ro_gui_wimp_event_open_window(open))
+ return;
+
+ error = xwimp_open_window(open);
+ if (error) {
+ LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+}
+
+
+/**
+ * source bounce callback.
+ */
+static void ro_gui_view_source_bounce(wimp_message *message)
+{
+ char *filename;
+ os_error *error;
+ char command[256];
+
+ /* run the file as text */
+ filename = ((wimp_full_message_data_xfer *)message)->file_name;
+ sprintf(command, "@RunType_FFF %s", filename);
+ error = xwimp_start_task(command, 0);
+ if (error) {
+ LOG("xwimp_start_task failed: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+}
+
+
+/**
+ * Send the source of a content to a text editor.
+ */
+void ro_gui_view_source(hlcache_handle *c)
+{
+ os_error *error;
+ char *temp_name;
+ wimp_full_message_data_xfer message;
+ int objtype;
+ bool done = false;
+
+ const char *source_data;
+ unsigned long source_size;
+
+ if (!c) {
+ ro_warn_user("MiscError", "No document source");
+ return;
+ }
+
+ source_data = content_get_source_data(c, &source_size);
+
+ if (!source_data) {
+ ro_warn_user("MiscError", "No document source");
+ return;
+ }
+
+ /* try to load local files directly. */
+ if (netsurf_nsurl_to_path(hlcache_handle_get_url(c), &temp_name) == NSERROR_OK) {
+ error = xosfile_read_no_path(temp_name, &objtype, 0, 0, 0, 0);
+ if ((!error) && (objtype == osfile_IS_FILE)) {
+ snprintf(message.file_name, 212, "%s", temp_name);
+ message.file_name[211] = '\0';
+ done = true;
+ }
+ free(temp_name);
+ }
+ if (!done) {
+ /* We cannot release the requested filename until after it
+ * has finished being used. As we can't easily find out when
+ * this is, we simply don't bother releasing it and simply
+ * allow it to be re-used next time NetSurf is started. The
+ * memory overhead from doing this is under 1 byte per
+ * filename. */
+ char *r;
+ char full_name[256];
+ const char *filename = filename_request();
+ if (!filename) {
+ ro_warn_user("NoMemory", 0);
+ return;
+ }
+
+ snprintf(full_name, 256, "%s/%s", TEMP_FILENAME_PREFIX,
+ filename);
+ full_name[255] = '\0';
+ r = __riscosify(full_name, 0, __RISCOSIFY_NO_SUFFIX,
+ message.file_name, 212, 0);
+ if (r == 0) {
+ LOG("__riscosify failed");
+ return;
+ }
+ message.file_name[211] = '\0';
+
+ error = xosfile_save_stamped(message.file_name,
+ ro_content_filetype(c),
+ (byte *) source_data,
+ (byte *) source_data + source_size);
+ if (error) {
+ LOG("xosfile_save_stamped failed: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ return;
+ }
+ }
+
+ /* begin the DataOpen protocol */
+ message.your_ref = 0;
+ message.size = 44 + ((strlen(message.file_name) + 4) & (~3u));
+ message.action = message_DATA_OPEN;
+ message.w = 0;
+ message.i = 0;
+ message.pos.x = 0;
+ message.pos.y = 0;
+ message.est_size = 0;
+ message.file_type = 0xfff;
+ ro_message_send_message(wimp_USER_MESSAGE_RECORDED,
+ (wimp_message*)&message, 0,
+ ro_gui_view_source_bounce);
+}
+
+
+/**
+ * Broadcast an URL that we can't handle.
+ */
+static nserror gui_launch_url(struct nsurl *url)
+{
+ /* Try ant broadcast */
+ ro_url_broadcast(nsurl_access(url));
+ return NSERROR_OK;
+}
+
+
+/**
+ * Choose the language to use.
+ */
+static void ro_gui_choose_language(void)
+{
+ /* if option_language exists and is valid, use that */
+ if (nsoption_charp(language)) {
+ char path[40];
+ if (2 < strlen(nsoption_charp(language)))
+ nsoption_charp(language)[2] = 0;
+ sprintf(path, "NetSurf:Resources.%s", nsoption_charp(language));
+
+ if (is_dir(path)) {
+ nsoption_setnull_charp(accept_language,
+ strdup(nsoption_charp(language)));
+ return;
+ }
+ nsoption_set_charp(language, NULL);
+ }
+
+ nsoption_set_charp(language, strdup(ro_gui_default_language()));
+ if (nsoption_charp(language) == NULL)
+ die("Out of memory");
+ nsoption_set_charp(accept_language, strdup(nsoption_charp(language)));
+ if (nsoption_charp(accept_language) == NULL)
+ die("Out of memory");
+}
+
+
+/**
+ * Display a warning for a serious problem (eg memory exhaustion).
+ *
+ * \param warning message key for warning message
+ * \param detail additional message, or 0
+ */
+nserror ro_warn_user(const char *warning, const char *detail)
+{
+ LOG("%s %s", warning, detail);
+
+ if (dialog_warning) {
+ char warn_buffer[300];
+ snprintf(warn_buffer, sizeof warn_buffer, "%s %s",
+ messages_get(warning),
+ detail ? detail : "");
+ warn_buffer[sizeof warn_buffer - 1] = 0;
+ ro_gui_set_icon_string(dialog_warning, ICON_WARNING_MESSAGE,
+ warn_buffer, true);
+ xwimp_set_icon_state(dialog_warning, ICON_WARNING_HELP,
+ wimp_ICON_DELETED, wimp_ICON_DELETED);
+ ro_gui_dialog_open(dialog_warning);
+ xos_bell();
+ } else {
+ /* probably haven't initialised (properly), use a
+ non-multitasking error box */
+ os_error error;
+ snprintf(error.errmess, sizeof error.errmess, "%s %s",
+ messages_get(warning),
+ detail ? detail : "");
+ error.errmess[sizeof error.errmess - 1] = 0;
+ xwimp_report_error_by_category(&error,
+ wimp_ERROR_BOX_OK_ICON |
+ wimp_ERROR_BOX_GIVEN_CATEGORY |
+ wimp_ERROR_BOX_CATEGORY_ERROR <<
+ wimp_ERROR_BOX_CATEGORY_SHIFT,
+ "NetSurf", "!netsurf",
+ (osspriteop_area *) 1, 0, 0);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Display an error and exit.
+ *
+ * Should only be used during initialisation.
+ */
+void die(const char * const error)
+{
+ os_error warn_error;
+
+ LOG("%s", error);
+
+ warn_error.errnum = 1; /* \todo: reasonable ? */
+ strncpy(warn_error.errmess, messages_get(error),
+ sizeof(warn_error.errmess)-1);
+ warn_error.errmess[sizeof(warn_error.errmess)-1] = '\0';
+ xwimp_report_error_by_category(&warn_error,
+ wimp_ERROR_BOX_OK_ICON |
+ wimp_ERROR_BOX_GIVEN_CATEGORY |
+ wimp_ERROR_BOX_CATEGORY_ERROR <<
+ wimp_ERROR_BOX_CATEGORY_SHIFT,
+ "NetSurf", "!netsurf",
+ (osspriteop_area *) 1, 0, 0);
+ exit(EXIT_FAILURE);
+}
+
+
+/**
+ * Test whether it's okay to shutdown, prompting the user if not.
+ *
+ * \return true iff it's okay to shutdown immediately
+ */
+bool ro_gui_prequit(void)
+{
+ return ro_gui_download_prequit();
+}
+
+
+/**
+ * Generate a riscos path from one or more component elemnts.
+ *
+ * Constructs a complete path element from passed components. The
+ * second (and subsequent) components have a slash substituted for all
+ * riscos directory separators.
+ *
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nelm The number of elements.
+ * @param[in] ap The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror riscos_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
+{
+ const char *elm[16];
+ size_t elm_len[16];
+ size_t elm_idx;
+ char *fname;
+ size_t fname_len = 0;
+ char *curp;
+ size_t idx;
+
+ /* check the parameters are all sensible */
+ if ((nelm == 0) || (nelm > 16)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if ((*str != NULL) && (size == NULL)) {
+ /* if the caller is providing the buffer they must say
+ * how much space is available.
+ */
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* calculate how much storage we need for the complete path
+ * with all the elements.
+ */
+ for (elm_idx = 0; elm_idx < nelm; elm_idx++) {
+ elm[elm_idx] = va_arg(ap, const char *);
+ /* check the argument is not NULL */
+ if (elm[elm_idx] == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ elm_len[elm_idx] = strlen(elm[elm_idx]);
+ fname_len += elm_len[elm_idx];
+ }
+ fname_len += nelm; /* allow for separators and terminator */
+
+ /* ensure there is enough space */
+ fname = *str;
+ if (fname != NULL) {
+ if (fname_len > *size) {
+ return NSERROR_NOSPACE;
+ }
+ } else {
+ fname = malloc(fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* copy the elements in with directory separator */
+ curp = fname;
+
+ /* first element is not altered */
+ memmove(curp, elm[0], elm_len[0]);
+ curp += elm_len[0];
+ /* ensure there is a delimiter */
+ if (curp[-1] != DIR_SEP) {
+ *curp = DIR_SEP;
+ curp++;
+ }
+
+ /* subsequent elemnts have slashes substituted with directory
+ * separators.
+ */
+ for (elm_idx = 1; elm_idx < nelm; elm_idx++) {
+ for (idx = 0; idx < elm_len[elm_idx]; idx++) {
+ if (elm[elm_idx][idx] == DIR_SEP) {
+ *curp = '/';
+ } else {
+ *curp = elm[elm_idx][idx];
+ }
+ curp++;
+ }
+ *curp = DIR_SEP;
+ curp++;
+ }
+ curp[-1] = 0; /* NULL terminate */
+
+ assert((curp - fname) <= (int)fname_len);
+
+ *str = fname;
+ if (size != NULL) {
+ *size = fname_len;
+ }
+
+ return NSERROR_OK;
+
+}
+
+
+/**
+ * Get the basename of a file using posix path handling.
+ *
+ * This gets the last element of a path and returns it. The returned
+ * element has all forward slashes translated into riscos directory
+ * separators.
+ *
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror riscos_basename(const char *path, char **str, size_t *size)
+{
+ const char *leafname;
+ char *fname;
+ char *temp;
+
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ leafname = strrchr(path, DIR_SEP);
+ if (!leafname) {
+ leafname = path;
+ } else {
+ leafname += 1;
+ }
+
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /** @todo check this leafname translation is actually required */
+ /* and s/\//\./g */
+ for (temp = fname; *temp != 0; temp++) {
+ if (*temp == '/') {
+ *temp = DIR_SEP;
+ }
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Ensure that all directory elements needed to store a filename exist.
+ *
+ * Given a path of x.y.z directories x and x.y will be created.
+ *
+ * @param fname The filename to ensure the path to exists.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+static nserror riscos_mkdir_all(const char *fname)
+{
+ char *dname;
+ char *cur;
+
+ dname = strdup(fname);
+
+ cur = dname;
+ while ((cur = strchr(cur, '.'))) {
+ *cur = '\0';
+ xosfile_create_dir(dname, 0);
+ *cur++ = '.';
+ }
+
+ free(dname);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Find screen size in OS units.
+ */
+void ro_gui_screen_size(int *width, int *height)
+{
+ *width = screen_info.width;
+ *height = screen_info.height;
+}
+
+
+/**
+ * Send the debug dump of a content to a text editor.
+ */
+void ro_gui_dump_browser_window(struct browser_window *bw)
+{
+ os_error *error;
+
+ /* open file for dump */
+ FILE *stream = fopen("<Wimp$ScrapDir>.WWW.NetSurf.dump", "w");
+ if (!stream) {
+ LOG("fopen: errno %i", errno);
+ ro_warn_user("SaveError", strerror(errno));
+ return;
+ }
+
+ browser_window_debug_dump(bw, stream, CONTENT_DEBUG_RENDER);
+
+ fclose(stream);
+
+ /* launch file in editor */
+ error = xwimp_start_task("Filer_Run <Wimp$ScrapDir>.WWW.NetSurf.dump",
+ 0);
+ if (error) {
+ LOG("xwimp_start_task failed: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+}
+
+
+static struct gui_file_table riscos_file_table = {
+ .mkpath = riscos_mkpath,
+ .basename = riscos_basename,
+ .nsurl_to_path = ro_nsurl_to_path,
+ .path_to_nsurl = ro_path_to_nsurl,
+ .mkdir_all = riscos_mkdir_all,
+};
+
+static struct gui_fetch_table riscos_fetch_table = {
+ .filetype = fetch_filetype,
+
+ .get_resource_url = gui_get_resource_url,
+ .mimetype = fetch_mimetype,
+};
+
+static struct gui_misc_table riscos_misc_table = {
+ .schedule = riscos_schedule,
+ .warning = ro_warn_user,
+
+ .quit = gui_quit,
+ .launch_url = gui_launch_url,
+ .cert_verify = gui_cert_verify,
+ .login = gui_401login_open,
+};
+
+
+static char *get_cachepath(void)
+{
+ char *cachedir;
+ char *cachepath = NULL;
+ nserror ret;
+
+ cachedir = getenv("Cache$Dir");
+ if ((cachedir == NULL) || (cachedir[0] == 0)) {
+ LOG("cachedir was null");
+ return NULL;
+ }
+ ret = netsurf_mkpath(&cachepath, NULL, 2, cachedir, "NetSurf");
+ if (ret != NSERROR_OK) {
+ return NULL;
+ }
+ return cachepath;
+}
+
+/**
+ * Normal entry point from RISC OS.
+ */
+int main(int argc, char** argv)
+{
+ char *cachepath;
+ char path[40];
+ int length;
+ os_var_type type;
+ int used = -1; /* slightly better with older OSLib versions */
+ os_error *error;
+ nserror ret;
+ struct netsurf_table riscos_table = {
+ .misc = &riscos_misc_table,
+ .window = riscos_window_table,
+ .clipboard = riscos_clipboard_table,
+ .download = riscos_download_table,
+ .fetch = &riscos_fetch_table,
+ .file = &riscos_file_table,
+ .utf8 = riscos_utf8_table,
+ .search = riscos_search_table,
+ .llcache = filesystem_llcache_table,
+ .bitmap = riscos_bitmap_table,
+ .layout = riscos_layout_table,
+ };
+
+ ret = netsurf_register(&riscos_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table failed registration");
+ }
+
+ /* Consult NetSurf$Logging environment variable to decide if logging
+ * is required. */
+ error = xos_read_var_val_size("NetSurf$Logging", 0, os_VARTYPE_STRING,
+ &used, NULL, &type);
+ if (error != NULL || type != os_VARTYPE_STRING || used != -2) {
+ verbose_log = true;
+ } else {
+ char logging_env[2];
+ error = xos_read_var_val("NetSurf$Logging", logging_env,
+ sizeof(logging_env), 0, os_VARTYPE_STRING,
+ &used, NULL, &type);
+ if (error != NULL || logging_env[0] != '0') {
+ verbose_log = true;
+ } else {
+ verbose_log = false;
+ }
+ }
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, &argc, argv);
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ die("Options failed to initialise");
+ }
+ nsoption_read("NetSurf:Choices", NULL);
+ nsoption_commandline(&argc, argv, NULL);
+
+ /* Choose the interface language to use */
+ ro_gui_choose_language();
+
+ /* select language-specific Messages */
+ if (((length = snprintf(path,
+ sizeof(path),
+ "NetSurf:Resources.%s.Messages",
+ nsoption_charp(language))) < 0) ||
+ (length >= (int)sizeof(path))) {
+ die("Failed to locate Messages resource.");
+ }
+
+ /* initialise messages */
+ messages_add_from_file(path);
+
+ /* obtain cache path */
+ cachepath = get_cachepath();
+
+ /* common initialisation */
+ ret = netsurf_init(cachepath);
+ free(cachepath);
+ if (ret != NSERROR_OK) {
+ die("NetSurf failed to initialise core");
+ }
+
+ artworks_init();
+ draw_init();
+ sprite_init();
+
+ /* Load some extra RISC OS specific Messages */
+ messages_add_from_file("NetSurf:Resources.LangNames");
+
+ ret = gui_init(argc, argv);
+ if (ret != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(ret), 0);
+ }
+
+ while (!riscos_done) {
+ riscos_poll();
+ }
+
+ netsurf_exit();
+
+ return 0;
+}
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
new file mode 100644
index 000000000..624f9e2fb
--- /dev/null
+++ b/frontends/riscos/gui.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_RISCOS_GUI_H_
+#define _NETSURF_RISCOS_GUI_H_
+
+#include <oslib/wimp.h>
+
+#define RISCOS5 0xAA
+
+#define THUMBNAIL_WIDTH 100
+#define THUMBNAIL_HEIGHT 86
+
+/* The maximum size for user-editable URLs in the RISC OS GUI. */
+
+#define RO_GUI_MAX_URL_SIZE 2048
+
+extern int os_version;
+
+extern const char * NETSURF_DIR;
+
+struct toolbar;
+struct status_bar;
+struct plotter_table;
+struct gui_window;
+struct tree;
+struct node;
+struct history;
+struct css_style;
+struct ssl_cert_info;
+struct nsurl;
+struct hlcache_handle;
+
+enum gui_pointer_shape;
+
+extern wimp_t task_handle; /**< RISC OS wimp task handle. */
+
+extern wimp_w dialog_info, dialog_saveas, dialog_zoom, dialog_pageinfo,
+ dialog_objinfo, dialog_tooltip, dialog_warning, dialog_openurl,
+ dialog_folder, dialog_entry, dialog_url_complete,
+ dialog_search, dialog_print, dialog_theme_install;
+extern wimp_w current_menu_window;
+extern bool current_menu_open;
+extern wimp_menu *recent_search_menu; /* search.c */
+extern wimp_w history_window;
+extern bool gui_redraw_debug;
+extern osspriteop_area *gui_sprites;
+extern bool dialog_folder_add, dialog_entry_add, hotlist_insert;
+extern bool print_active, print_text_black;
+extern bool no_font_blending;
+
+typedef enum { GUI_DRAG_NONE, GUI_DRAG_DOWNLOAD_SAVE, GUI_DRAG_SAVE }
+ ro_gui_drag_type;
+
+extern ro_gui_drag_type gui_current_drag_type;
+
+extern bool riscos_done;
+
+/** RISC OS data for a browser window. */
+struct gui_window {
+ /** Associated platform-independent browser window data. */
+ struct browser_window *bw;
+
+ struct toolbar *toolbar; /**< Toolbar, or 0 if not present. */
+ struct status_bar *status_bar; /**< Status bar, or 0 if not present. */
+
+ wimp_w window; /**< RISC OS window handle. */
+
+ int old_width; /**< Width when last opened / os units. */
+ int old_height; /**< Height when last opened / os units. */
+ bool update_extent; /**< Update the extent on next opening */
+ bool active; /**< Whether the throbber should be active */
+
+ char title[256]; /**< Buffer for window title. */
+
+ int iconise_icon; /**< ID number of icon when window is iconised */
+
+ char validation[12]; /**< Validation string for colours */
+
+ float scale; /**< Browser window scale */
+
+ /** Options. */
+ struct {
+ bool buffer_animations; /**< Use screen buffering for animations. */
+ bool buffer_everything; /**< Use screen buffering for everything. */
+ } option;
+
+ struct gui_window *prev; /**< Previous in linked list. */
+ struct gui_window *next; /**< Next in linked list. */
+};
+
+
+extern struct gui_window *ro_gui_current_redraw_gui;
+
+
+/* in gui.c */
+void ro_gui_open_window_request(wimp_open *open);
+void ro_gui_screen_size(int *width, int *height);
+void ro_gui_view_source(struct hlcache_handle *c);
+void ro_gui_dump_browser_window(struct browser_window *bw);
+void ro_gui_drag_box_start(wimp_pointer *pointer);
+bool ro_gui_prequit(void);
+const char *ro_gui_default_language(void);
+nserror ro_warn_user(const char *warning, const char *detail);
+
+/**
+ * Cause an abnormal program termination.
+ *
+ * \note This never returns and is intended to terminate without any cleanup.
+ *
+ * \param error The message to display to the user.
+ */
+void die(const char * const error) __attribute__ ((noreturn));
+
+/* in download.c */
+void ro_gui_download_init(void);
+void ro_gui_download_datasave_ack(wimp_message *message);
+bool ro_gui_download_prequit(void);
+extern struct gui_download_table *riscos_download_table;
+
+/* in 401login.c */
+void ro_gui_401login_init(void);
+void gui_401login_open(struct nsurl *url, const char *realm,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+/* in window.c */
+void ro_gui_window_set_scale(struct gui_window *g, float scale);
+bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message);
+void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data);
+void ro_gui_window_iconise(struct gui_window *g,
+ wimp_full_message_window_info *wi);
+bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message);
+void ro_gui_window_redraw_all(void);
+void ro_gui_window_update_boxes(void);
+void ro_gui_window_quit(void);
+/* void ro_gui_window_close_all(void); */
+#define ro_gui_window_close_all ro_gui_window_quit /* no need for a separate fn */
+void ro_gui_throb(void);
+void ro_gui_window_default_options(struct gui_window *gui);
+struct gui_window *ro_gui_window_lookup(wimp_w window);
+struct gui_window *ro_gui_toolbar_lookup(wimp_w window);
+bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y,
+ os_coord *pos);
+bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y,
+ os_coord *pos);
+enum browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
+ wimp_icon_flags type);
+enum browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
+ wimp_icon_flags type);
+bool ro_gui_shift_pressed(void);
+bool ro_gui_ctrl_pressed(void);
+bool ro_gui_alt_pressed(void);
+void gui_window_set_pointer(struct gui_window *g, enum gui_pointer_shape shape);
+
+/* in history.c */
+void ro_gui_history_init(void);
+void ro_gui_history_open(struct gui_window *g, bool pointer);
+
+/* in schedule.c */
+extern bool sched_active;
+extern os_t sched_time;
+
+/**
+ * Process events up to current time.
+ */
+bool schedule_run(void);
+
+/**
+ * Schedule a callback.
+ *
+ * \param t interval before the callback should be made in ms
+ * \param callback callback function
+ * \param p user parameter, passed to callback function
+ *
+ * The callback function will be called as soon as possible after t ms have
+ * passed.
+ */
+nserror riscos_schedule(int t, void (*callback)(void *p), void *p);
+
+/* in search.c */
+void ro_gui_search_init(void);
+void ro_gui_search_prepare(struct browser_window *g);
+struct gui_search_table *riscos_search_table;
+
+/* in print.c */
+void ro_gui_print_init(void);
+void ro_gui_print_prepare(struct gui_window *g);
+
+/* in plotters.c */
+extern const struct plotter_table ro_plotters;
+extern int ro_plot_origin_x;
+extern int ro_plot_origin_y;
+
+/* in theme_install.c */
+bool ro_gui_theme_install_apply(wimp_w w);
+
+/* in sslcert.c */
+void gui_cert_verify(struct nsurl *url,
+ const struct ssl_cert_info *certs, unsigned long num,
+ nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+/* icon numbers */
+#define ICON_STATUS_RESIZE 0
+#define ICON_STATUS_TEXT 1
+
+#define ICON_SAVE_ICON 0
+#define ICON_SAVE_PATH 1
+#define ICON_SAVE_OK 2
+#define ICON_SAVE_CANCEL 3
+
+#define ICON_PAGEINFO_TITLE 0
+#define ICON_PAGEINFO_URL 1
+#define ICON_PAGEINFO_ENC 2
+#define ICON_PAGEINFO_TYPE 3
+#define ICON_PAGEINFO_ICON 4
+
+#define ICON_OBJINFO_URL 0
+#define ICON_OBJINFO_TARGET 1
+#define ICON_OBJINFO_TYPE 2
+#define ICON_OBJINFO_ICON 3
+
+#define ICON_WARNING_MESSAGE 0
+#define ICON_WARNING_CONTINUE 1
+#define ICON_WARNING_HELP 2
+
+#define ICON_SEARCH_TEXT 0
+#define ICON_SEARCH_CASE_SENSITIVE 1
+#define ICON_SEARCH_FIND_NEXT 2
+#define ICON_SEARCH_FIND_PREV 3
+#define ICON_SEARCH_CANCEL 4
+#define ICON_SEARCH_STATUS 5
+#define ICON_SEARCH_MENU 8
+#define ICON_SEARCH_SHOW_ALL 9
+
+#define ICON_THEME_INSTALL_MESSAGE 0
+#define ICON_THEME_INSTALL_INSTALL 1
+#define ICON_THEME_INSTALL_CANCEL 2
+
+#define ICON_OPENURL_URL 1
+#define ICON_OPENURL_CANCEL 2
+#define ICON_OPENURL_OPEN 3
+#define ICON_OPENURL_MENU 4
+
+#define ICON_ENTRY_NAME 1
+#define ICON_ENTRY_URL 3
+#define ICON_ENTRY_CANCEL 4
+#define ICON_ENTRY_OK 5
+#define ICON_ENTRY_RECENT 6
+
+#define ICON_FOLDER_NAME 1
+#define ICON_FOLDER_CANCEL 2
+#define ICON_FOLDER_OK 3
+
+#endif
diff --git a/frontends/riscos/gui/button_bar.c b/frontends/riscos/gui/button_bar.c
new file mode 100644
index 000000000..6ecd7cffa
--- /dev/null
+++ b/frontends/riscos/gui/button_bar.c
@@ -0,0 +1,1229 @@
+/*
+ * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2011 Stephen Fryatt <stevef@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Button bars (implementation).
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oslib/dragasprite.h>
+#include <oslib/os.h>
+#include <oslib/osspriteop.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpspriteop.h>
+
+#include "utils/log.h"
+
+#include "riscos/gui/button_bar.h"
+#include "riscos/gui.h"
+#include "riscos/mouse.h"
+#include "riscos/theme.h"
+#include "riscos/wimp.h"
+
+#define BUTTONBAR_SPRITE_NAME_LENGTH 12
+#define BUTTONBAR_VALIDATION_LENGTH 40
+
+struct button_bar_button {
+ wimp_i icon;
+ bool shaded;
+ bool separator;
+
+ button_bar_action select_action;
+ button_bar_action adjust_action;
+
+ int x_pos, y_pos;
+ int x_size, y_size;
+
+ char sprite[BUTTONBAR_SPRITE_NAME_LENGTH];
+ char validation[BUTTONBAR_VALIDATION_LENGTH];
+ char opt_key;
+ const char *help_suffix;
+
+ struct button_bar_button *bar_next;
+ struct button_bar_button *next;
+};
+
+
+struct button_bar {
+ /** The applied theme (or NULL to use the default) */
+ struct theme_descriptor *theme;
+
+ /** The widget dimensions. */
+ int x_min, y_min;
+ int separator_width;
+ int vertical_offset;
+
+ bool separators;
+
+ /** The window details and bar position. */
+ wimp_w window;
+ os_box extent;
+ osspriteop_area *sprites;
+ int background;
+
+ bool hidden;
+
+ bool edit;
+ struct button_bar *edit_target;
+ struct button_bar *edit_source;
+ void (*edit_refresh)(void *);
+ void *edit_client_data;
+
+ /** The list of all the defined buttons. */
+
+ struct button_bar_button *buttons;
+
+ /** The list of the buttons in the current bar. */
+
+ struct button_bar_button *bar;
+};
+
+static char null_text_string[] = "";
+static char separator_name[] = "separator";
+
+static struct button_bar *drag_start = NULL;
+static char drag_opt = '\0';
+static bool drag_separator = false;
+
+/*
+ * Private function prototypes.
+ */
+
+static bool ro_gui_button_bar_place_buttons(struct button_bar *button_bar);
+static bool ro_gui_button_bar_icon_update(struct button_bar *button_bar);
+static bool ro_gui_button_bar_icon_resize(struct button_bar *button_bar);
+static void ro_gui_button_bar_drag_end(wimp_dragged *drag, void *data);
+static void ro_gui_button_bar_sync_editors(struct button_bar *target,
+ struct button_bar *source);
+static struct button_bar_button *ro_gui_button_bar_find_icon(
+ struct button_bar *button_bar, wimp_i icon);
+static struct button_bar_button *ro_gui_button_bar_find_opt_key(
+ struct button_bar *button_bar, char opt_key);
+static struct button_bar_button *ro_gui_button_bar_find_action(
+ struct button_bar *button_bar, button_bar_action action);
+static struct button_bar_button *ro_gui_button_bar_find_coords(
+ struct button_bar *button_bar, os_coord pos,
+ bool *separator, bool *right);
+
+/* This is an exported interface documented in button_bar.h */
+
+struct button_bar *ro_gui_button_bar_create(struct theme_descriptor *theme,
+ const struct button_bar_buttons buttons[])
+{
+ struct button_bar *button_bar;
+ struct button_bar_button *icon, *new_icon;
+ int def;
+
+ /* Allocate memory. */
+
+ button_bar = malloc(sizeof(struct button_bar));
+ if (button_bar == NULL) {
+ LOG("No memory for malloc()");
+ return NULL;
+ }
+
+ /* Set up default parameters. */
+
+ button_bar->theme = theme;
+ button_bar->sprites = ro_gui_theme_get_sprites(theme);
+ button_bar->background = wimp_COLOUR_VERY_LIGHT_GREY;
+
+ button_bar->x_min = -1;
+ button_bar->y_min = -1;
+ button_bar->separator_width = 0;
+ button_bar->vertical_offset = 0;
+
+ button_bar->separators = false;
+
+ button_bar->window = NULL;
+
+ button_bar->hidden = false;
+
+ button_bar->edit = false;
+ button_bar->edit_target = NULL;
+ button_bar->edit_source = NULL;
+ button_bar->edit_refresh = NULL;
+ button_bar->edit_client_data = NULL;
+
+ button_bar->buttons = NULL;
+
+ /* Process the button icon definitions */
+
+ icon = NULL;
+
+ for (def = 0; buttons[def].icon != NULL; def++) {
+ new_icon = malloc(sizeof(struct button_bar_button));
+ if (new_icon == NULL) {
+ break;
+ }
+
+ if (icon == NULL) {
+ button_bar->buttons = new_icon;
+ button_bar->bar = new_icon;
+ } else {
+ icon->next = new_icon;
+ icon->bar_next = new_icon;
+ }
+ icon = new_icon;
+ icon->next = NULL;
+ icon->bar_next = NULL;
+
+ strncpy(icon->sprite, buttons[def].icon,
+ BUTTONBAR_SPRITE_NAME_LENGTH);
+ snprintf(icon->validation, BUTTONBAR_VALIDATION_LENGTH,
+ "R5;S%s,p%s", icon->sprite, icon->sprite);
+
+ icon->icon = -1;
+ icon->shaded = false;
+ icon->separator = false;
+
+ icon->select_action = buttons[def].select;
+ icon->adjust_action = buttons[def].adjust;
+ icon->opt_key = buttons[def].opt_key;
+ icon->help_suffix = buttons[def].help;
+ }
+
+ /* Add a separator after the last entry. This will be lost if the
+ * buttons are subsequently set, but is used for the edit source bar.
+ */
+
+ if (icon != NULL)
+ icon->separator = true;
+
+ return button_bar;
+}
+
+
+/* This is an exported interface documented in button_bar.h */
+
+bool ro_gui_button_bar_link_editor(struct button_bar *target,
+ struct button_bar *source, void (* refresh)(void *),
+ void *client_data)
+{
+ if (target == NULL || source == NULL ||
+ target->edit_target != NULL ||
+ target->edit_source != NULL ||
+ source->edit_target != NULL ||
+ source->edi