From 5e41fb8a121c441a8765a1962a892e93906cde83 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Sun, 7 Nov 2004 19:19:11 +0000 Subject: [project @ 2004-11-07 19:19:11 by rjw] Initial import. svn path=/import/nstheme/; revision=2436 --- !NSTheme/!Boot,feb | 10 + !NSTheme/!Help | 23 ++ !NSTheme/!Run,feb | 20 ++ !NSTheme/!Sprites,ff9 | Bin 0 -> 1580 bytes !NSTheme/!Sprites22,ff9 | Bin 0 -> 3228 bytes !NSTheme/5Sprites,ff9 | Bin 0 -> 3092 bytes !NSTheme/5Sprites11,ff9 | Bin 0 -> 11132 bytes !NSTheme/5Sprites22,ff9 | Bin 0 -> 4868 bytes !NSTheme/ASprites,ff9 | Bin 0 -> 3664 bytes !NSTheme/ASprites11,ff9 | Bin 0 -> 15892 bytes !NSTheme/ASprites22,ff9 | Bin 0 -> 6092 bytes !NSTheme/Resources/en/Messages | 67 ++++ !NSTheme/Resources/en/Templates,fec | Bin 0 -> 2365 bytes desktop/gui.h | 22 ++ desktop/nstheme.c | 44 +++ desktop/nstheme.h | 16 + desktop/options.c | 149 +++++++++ desktop/options.h | 46 +++ makefile | 71 +++++ posix.mk | 11 + riscos.mk | 9 + riscos/dialog.c | 479 ++++++++++++++++++++++++++++ riscos/gui.c | 608 ++++++++++++++++++++++++++++++++++++ riscos/gui.h | 97 ++++++ riscos/help.c | 257 +++++++++++++++ riscos/help.h | 20 ++ riscos/menus.c | 272 ++++++++++++++++ riscos/options.h | 24 ++ riscos/save.c | 554 ++++++++++++++++++++++++++++++++ riscos/wimp.c | 556 +++++++++++++++++++++++++++++++++ riscos/wimp.h | 51 +++ utils/log.h | 26 ++ utils/messages.c | 169 ++++++++++ utils/messages.h | 29 ++ utils/utils.c | 30 ++ utils/utils.h | 23 ++ 36 files changed, 3683 insertions(+) create mode 100644 !NSTheme/!Boot,feb create mode 100644 !NSTheme/!Help create mode 100644 !NSTheme/!Run,feb create mode 100644 !NSTheme/!Sprites,ff9 create mode 100644 !NSTheme/!Sprites22,ff9 create mode 100644 !NSTheme/5Sprites,ff9 create mode 100644 !NSTheme/5Sprites11,ff9 create mode 100644 !NSTheme/5Sprites22,ff9 create mode 100644 !NSTheme/ASprites,ff9 create mode 100644 !NSTheme/ASprites11,ff9 create mode 100644 !NSTheme/ASprites22,ff9 create mode 100644 !NSTheme/Resources/en/Messages create mode 100644 !NSTheme/Resources/en/Templates,fec create mode 100644 desktop/gui.h create mode 100644 desktop/nstheme.c create mode 100644 desktop/nstheme.h create mode 100644 desktop/options.c create mode 100644 desktop/options.h create mode 100644 makefile create mode 100644 posix.mk create mode 100644 riscos.mk create mode 100644 riscos/dialog.c create mode 100644 riscos/gui.c create mode 100644 riscos/gui.h create mode 100644 riscos/help.c create mode 100644 riscos/help.h create mode 100644 riscos/menus.c create mode 100644 riscos/options.h create mode 100644 riscos/save.c create mode 100644 riscos/wimp.c create mode 100644 riscos/wimp.h create mode 100644 utils/log.h create mode 100644 utils/messages.c create mode 100644 utils/messages.h create mode 100644 utils/utils.c create mode 100644 utils/utils.h diff --git a/!NSTheme/!Boot,feb b/!NSTheme/!Boot,feb new file mode 100644 index 0000000..633652a --- /dev/null +++ b/!NSTheme/!Boot,feb @@ -0,0 +1,10 @@ +| Application system variables +Set NSTheme$Help .!Help +Set NSTheme$Version "0.01 (04 Sep 2004)" +Set NSTheme$Web "http://netsurf.sourceforge.net/" +Set NSTheme$Title "NSTheme" +Set NSTheme$Publisher "The NetSurf Developers" +Set NSTheme$Description "NetSurf theme editor" + +| NSTheme Sprites +If "" < "436" Then IconSprites .!Sprites Else If "" < "500" Then IconSprites .ASprites Else IconSprites .5Sprites diff --git a/!NSTheme/!Help b/!NSTheme/!Help new file mode 100644 index 0000000..dbf32f9 --- /dev/null +++ b/!NSTheme/!Help @@ -0,0 +1,23 @@ +NSTheme +======= +This application allows the creation and editing of !NetSurf themes. + + + +Theme file format +----------------- +[+0] 'NSTM' (0x4d54534e) +[+4] Minimum theme parser version required +[+8] Theme name (32 chars, null terminated) +[+40] Theme author (64 chars, null terminated) +[+104] Browser toolbar background (0x00-0x0f) +[+105] Hotlist toolbar background (0x00-0x0f) +[+106] Status bar background (0x00-0x0f) +[+107] Status bar foreground (0x00-0x0f) +[+108] Throbber is on the right (0x00) or left (0xff) +[+109] Reserved for future expansion (0x00) +[+110] Reserved for future expansion (0x00) +[+111] Reserved for future expansion (0x00) +[+112] Size of compressed sprite data +[+116] Size of uncompressed sprite data +[+120] Start of compressed sprite data diff --git a/!NSTheme/!Run,feb b/!NSTheme/!Run,feb new file mode 100644 index 0000000..1ee70c4 --- /dev/null +++ b/!NSTheme/!Run,feb @@ -0,0 +1,20 @@ +.!Boot + +| We need RISC OS 3.00 or greater +RMEnsure UtilityModule 3.00 Error NSTheme required RISC OS 3.00 or later + +| Ensure CallASWI is installed +| http://www.iyonix.com/32bit/ +RMEnsure UtilityModule 3.70 RMEnsure CallASWI 0.02 RMLoad System:Modules.CallASWI +RMEnsure UtilityModule 3.70 RMEnsure CallASWI 0.02 Error NSTheme requires the CallASWI module. This can be downloaded from http://www.iyonix.com/32bit/system.shtml + +| Ensure SharedUnixLibrary is installed +| http://www.chocky.org/unix/usage.html +RMEnsure SharedUnixLibrary 1.02 RMLoad System:Modules.SharedULib +RMEnsure SharedUnixLibrary 1.02 Error NSTheme requires SharedUnixLibrary 1.02 or later. This can be downloaded from http://www.chocky.org/unix/usage.html + +Wimpslot -min 160k -max 160k +Set NSTheme$Dir +Set NSTheme$Running yes +Run .!RunImage 2>.stderr +UnSet NSTheme$Running diff --git a/!NSTheme/!Sprites,ff9 b/!NSTheme/!Sprites,ff9 new file mode 100644 index 0000000..afc643c Binary files /dev/null and b/!NSTheme/!Sprites,ff9 differ diff --git a/!NSTheme/!Sprites22,ff9 b/!NSTheme/!Sprites22,ff9 new file mode 100644 index 0000000..ba77273 Binary files /dev/null and b/!NSTheme/!Sprites22,ff9 differ diff --git a/!NSTheme/5Sprites,ff9 b/!NSTheme/5Sprites,ff9 new file mode 100644 index 0000000..6daf777 Binary files /dev/null and b/!NSTheme/5Sprites,ff9 differ diff --git a/!NSTheme/5Sprites11,ff9 b/!NSTheme/5Sprites11,ff9 new file mode 100644 index 0000000..6bfaa62 Binary files /dev/null and b/!NSTheme/5Sprites11,ff9 differ diff --git a/!NSTheme/5Sprites22,ff9 b/!NSTheme/5Sprites22,ff9 new file mode 100644 index 0000000..2431eac Binary files /dev/null and b/!NSTheme/5Sprites22,ff9 differ diff --git a/!NSTheme/ASprites,ff9 b/!NSTheme/ASprites,ff9 new file mode 100644 index 0000000..2c2728c Binary files /dev/null and b/!NSTheme/ASprites,ff9 differ diff --git a/!NSTheme/ASprites11,ff9 b/!NSTheme/ASprites11,ff9 new file mode 100644 index 0000000..c0f822e Binary files /dev/null and b/!NSTheme/ASprites11,ff9 differ diff --git a/!NSTheme/ASprites22,ff9 b/!NSTheme/ASprites22,ff9 new file mode 100644 index 0000000..13c0662 Binary files /dev/null and b/!NSTheme/ASprites22,ff9 differ diff --git a/!NSTheme/Resources/en/Messages b/!NSTheme/Resources/en/Messages new file mode 100644 index 0000000..ed58fff --- /dev/null +++ b/!NSTheme/Resources/en/Messages @@ -0,0 +1,67 @@ +# English messages for NSTheme + +# Menus +NetSurf:NetSurf +Info:Info +AppHelp:Help... F1 +Quit:Quit +SaveAs:Save +Export:Export +SaveTitle:Save as +ExportTitle:Export sprites + +# Icon definitions +back:browser back icon +forward:browser forward icon +stop:browser stop icon +reload:browser reload icon +home:browser home icon +search:browser search icon +history:browser history icon +scale:browser scale icon +hotlist:browser hotlist icon +save:browser save icon +print:browser print icon +create:hotlist create entry icon +delete:hotlist delete entry icon +launch:hotlist launch icon +open:hotlist open directories icon +expand:hotlist expand entries icon +separator:toolbar separator +pushed: (pushed) + +# Report text +Title:NSTheme Sprites Report +WarnNoFile:Warning: No sprite file present. +WarnAlphaSpr:Warning: Sprite '%s' has an alpha channel specified. +WarnHighSpr:Warning: Sprite '%s' uses more than 256 colours. +WarnNoSpr:Warning: Sprite '%s' (%s%s) is missing. +WarnExtraSpr:Warning: Sprite '%s' is redundant. +WarnNoThrob:Warning: No throbber animation present. +WarnMissThrob:Warning: Throbber frame '%s' is missing. +CompleteErr:Analysis completed with %i warning(s). +CompleteOK:Analysis completed with no warnings. + +# Interactive help +HelpMain:\TNSTheme editing window.|MDrag a sprite file here to load it into the theme. +HelpMain3:\bwritable field specifies the theme name. +HelpMain5:\bwritable field specifies the theme author. +HelpMain8:\btick-box controls whether the theme throbber is on the left. +HelpMain11:\Sto view a report on the current sprites. +HelpMain12:\Sto remove the current sprites. +HelpMain16:\bis the current colour of the browser toolbar background. +HelpMain17:\Sto select the colour of the browser toolbar background. +HelpMain19:\bis the current colour of the hotlist toolbar background. +HelpMain20:\Sto select the colour of the hotlist toolbar background. +HelpMain22:\bis the current colour of the status bar background. +HelpMain23:\Sto select the colour of the status bar background. +HelpMain25:\bis the current colour of the status bar text. +HelpMain26:\Sto select the colour of the status bar text. +HelpAppInfo:\TNSTheme information \w. +HelpMainMenu0:\Rto save the theme. +HelpMainMenu1:\Rto export the theme sprites. +HelpMainMenu2:\Sview NSTheme's documentation. +HelpIconMenu0:\Rview information about this software. +HelpIconMenu1:\Sview NSTheme's documentation. +HelpIconMenu2:\Squit NSTheme. +HelpIconbar:\TNSTheme icon. \ No newline at end of file diff --git a/!NSTheme/Resources/en/Templates,fec b/!NSTheme/Resources/en/Templates,fec new file mode 100644 index 0000000..24e34a5 Binary files /dev/null and b/!NSTheme/Resources/en/Templates,fec differ diff --git a/desktop/gui.h b/desktop/gui.h new file mode 100644 index 0000000..f4069c1 --- /dev/null +++ b/desktop/gui.h @@ -0,0 +1,22 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * Interface to platform-specific gui functions. + */ + +#ifndef _NSTHEME_DESKTOP_GUI_H_ +#define _NSTHEME_DESKTOP_GUI_H_ + +#include + +void gui_init(void); +void gui_multitask(void); +void gui_poll(void); +void gui_exit(void); + +#endif diff --git a/desktop/nstheme.c b/desktop/nstheme.c new file mode 100644 index 0000000..d4e5a19 --- /dev/null +++ b/desktop/nstheme.c @@ -0,0 +1,44 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +#include +#include "nstheme/desktop/gui.h" +#include "nstheme/desktop/nstheme.h" +#include "nstheme/utils/utils.h" + +bool application_quit = false; + +static void application_init(void); +static void application_exit(void); + + +/** + * NSTheme main(). + */ +int main(int argc, char** argv) { + application_init(); + while (!application_quit) gui_poll(); + application_exit(); + return EXIT_SUCCESS; +} + + +/** + * Initialise application. + */ +void application_init(void) { + stdout = stderr; + gui_init(); +} + + +/** + * Finalise application. + */ +void application_exit(void) { + gui_exit(); +} diff --git a/desktop/nstheme.h b/desktop/nstheme.h new file mode 100644 index 0000000..fab28d3 --- /dev/null +++ b/desktop/nstheme.h @@ -0,0 +1,16 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +#ifndef _NSTHEME_DESKTOP_NSTHEME_H_ +#define _NSTHEME_DESKTOP_NSTHEME_H_ + +#include + +extern bool application_quit; + +#endif + diff --git a/desktop/options.c b/desktop/options.c new file mode 100644 index 0000000..b43291b --- /dev/null +++ b/desktop/options.c @@ -0,0 +1,149 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2003 John M Bell + * Copyright 2004 James Bursa + * Copyright 2004 Richard Wilson + */ + +/** \file + * Option reading and saving (implementation). + * + * Options are stored in the format key:value, one per line. For bool options, + * value is "0" or "1". + */ + +#include +#include +#include +#include "nstheme/desktop/options.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/utils.h" + +#ifdef riscos +#include "nstheme/riscos/options.h" +#else +#define EXTRA_OPTION_DEFINE +#define EXTRA_OPTION_TABLE +#endif + + +EXTRA_OPTION_DEFINE + + +struct { + const char *key; + enum { OPTION_BOOL, OPTION_INTEGER, OPTION_STRING } type; + void *p; +} option_table[] = { + EXTRA_OPTION_TABLE +}; + +#define option_table_entries (sizeof option_table / sizeof option_table[0]) + + +/** + * Read options from a file. + * + * \param path name of file to read options from + * + * Option variables corresponding to lines in the file are updated. Missing + * options are unchanged. If the file fails to open, options are unchanged. + */ + +void options_read(const char *path) +{ + char s[100]; + FILE *fp; + + fp = fopen(path, "r"); + if (!fp) { + LOG(("failed to open file '%s'", path)); + return; + } + + while (fgets(s, 100, fp)) { + char *colon, *value; + unsigned int i; + + if (s[0] == 0 || s[0] == '#') + continue; + colon = strchr(s, ':'); + if (colon == 0) + continue; + s[strlen(s) - 1] = 0; /* remove \n at end */ + *colon = 0; /* terminate key */ + value = colon + 1; + + for (i = 0; i != option_table_entries; i++) { + if (strcasecmp(s, option_table[i].key) != 0) + continue; + + switch (option_table[i].type) { + case OPTION_BOOL: + *((bool *) option_table[i].p) = + value[0] == '1'; + break; + + case OPTION_INTEGER: + *((int *) option_table[i].p) = + atoi(value); + break; + + case OPTION_STRING: + free(*((char **) option_table[i].p)); + *((char **) option_table[i].p) = + strdup(value); + break; + } + break; + } + } + + fclose(fp); +} + + +/** + * Save options to a file. + * + * \param path name of file to write options to + * + * Errors are ignored. + */ + +void options_write(const char *path) +{ + unsigned int i; + FILE *fp; + + fp = fopen(path, "w"); + if (!fp) { + LOG(("failed to open file '%s' for writing", path)); + return; + } + + for (i = 0; i != option_table_entries; i++) { + fprintf(fp, "%s:", option_table[i].key); + switch (option_table[i].type) { + case OPTION_BOOL: + fprintf(fp, "%c", *((bool *) option_table[i].p) ? + '1' : '0'); + break; + + case OPTION_INTEGER: + fprintf(fp, "%i", *((int *) option_table[i].p)); + break; + + case OPTION_STRING: + if (*((char **) option_table[i].p)) + fprintf(fp, "%s", *((char **) option_table[i].p)); + break; + } + fprintf(fp, "\n"); + } + + fclose(fp); +} diff --git a/desktop/options.h b/desktop/options.h new file mode 100644 index 0000000..ae35cda --- /dev/null +++ b/desktop/options.h @@ -0,0 +1,46 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2004 James Bursa + */ + +/** \file + * Option reading and saving (interface). + * + * Non-platform specific options can be added by editing this file and + * netsurf/desktop/options.c + * + * Platform specific options should be added in the platform options.h. + * + * The following types of options are supported: + * - bool (OPTION_BOOL) + * - int (OPTION_INTEGER) + * - char* (OPTION_STRING) (must be allocated on heap, may be 0, free before + * assigning a new value) + */ + +#ifndef _NETSURF_DESKTOP_OPTIONS_H_ +#define _NETSURF_DESKTOP_OPTIONS_H_ + +enum { OPTION_HTTP_PROXY_AUTH_NONE = 0, OPTION_HTTP_PROXY_AUTH_BASIC = 1, + OPTION_HTTP_PROXY_AUTH_NTLM = 2 }; + +extern bool option_http_proxy; +extern char *option_http_proxy_host; +extern int option_http_proxy_port; +extern int option_http_proxy_auth; +extern char *option_http_proxy_auth_user; +extern char *option_http_proxy_auth_pass; +extern int option_font_size; +extern int option_font_min_size; +extern char *option_accept_language; +extern bool option_ssl_verify_certificates; +extern int option_memory_cache_size; +extern bool option_block_ads; + +void options_read(const char *path); +void options_write(const char *path); + +#endif diff --git a/makefile b/makefile new file mode 100644 index 0000000..71bb865 --- /dev/null +++ b/makefile @@ -0,0 +1,71 @@ +# +# This file is part of NetSurf, http://netsurf.sourceforge.net/ +# Licensed under the GNU General Public License, +# http://www.opensource.org/licenses/gpl-license +# + +# There is 1 possible build of NSTheme: +# +# riscos -- standard RISC OS build +# +# "riscos" can be compiled under RISC OS, or cross-compiled using gccsdk. + +OBJECTS_COMMON = messages.o utils.o # utils/ +OBJECTS_COMMON += nstheme.o options.o # desktop/ + +OBJECTS_RISCOS = $(OBJECTS_COMMON) +OBJECTS_RISCOS += dialog.o gui.o help.o menus.o wimp.o save.o + + +OBJDIR_RISCOS = $(shell $(CC) -dumpmachine) +SOURCES_RISCOS=$(OBJECTS_RISCOS:.o=.c) +OBJS_RISCOS=$(OBJECTS_RISCOS:%.o=$(OBJDIR_RISCOS)/%.o) + +# Inclusion of platform specific files has to occur after the OBJDIR stuff as +# that is refered to in the files + +OS = $(word 2,$(subst -, ,$(shell gcc -dumpmachine))) +ifeq ($(OS),riscos) +include riscos.mk +else +include posix.mk +endif + +VPATH = desktop:riscos:utils + +WARNFLAGS = -W -Wall -Wundef -Wpointer-arith -Wcast-qual \ + -Wcast-align -Wwrite-strings -Wstrict-prototypes \ + -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls \ + -Wnested-externs -Winline -Wno-unused-parameter -Wuninitialized + +# CFLAGS have to appear after the inclusion of platform specific files as the +# PLATFORM_CFLAGS variables are defined in them + +CFLAGS_RISCOS = -std=c9x -D_BSD_SOURCE -Driscos -DBOOL_DEFINED -O2 \ + $(WARNFLAGS) -I.. $(PLATFORM_CFLAGS_RISCOS) -mpoke-function-name \ + +# targets +riscos: $(RUNIMAGE) +$(RUNIMAGE) : $(OBJS_RISCOS) + $(CC) -o $@ $(LDFLAGS_RISCOS) $^ + +netsurf.zip: $(RUNIMAGE) + rm nstheme.zip; riscos-zip -9vr, nstheme.zip !NSTheme + +# pattern rule for c source +$(OBJDIR_RISCOS)/%.o : %.c + @echo "==> $<" + @$(CC) -o $@ -c $(CFLAGS_RISCOS) $< + +# generate dependencies +depend : $(SOURCES_RISCOS) + -mkdir $(OBJDIR_RISCOS) + $(CC) -MM -MG $(CFLAGS_RISCOS) $^ | sed 's|.*\.o:|$(OBJDIR_RISCOS)/&|g' > depend + +# remove generated files +clean : + -rm $(OBJDIR_RISCOS) + +ifneq ($(OS),riscos) +include depend +endif diff --git a/posix.mk b/posix.mk new file mode 100644 index 0000000..1734364 --- /dev/null +++ b/posix.mk @@ -0,0 +1,11 @@ +CC = /riscos/bin/gcc +CC_DEBUG = gcc + +PLATFORM_CFLAGS_RISCOS = +PLATFORM_CFLAGS_DEBUG = -I/usr/include/libxml2 -I/riscos/src/OSLib \ + -I/riscos/include/libjpeg -D_POSIX_C_SOURCE + +LDFLAGS_RISCOS = -L/riscos/lib -lxml2 -lz -lcurl -lssl -lcrypto -lcares -lmng \ + -loslib -ljpeg + +RUNIMAGE = !NSTheme/!RunImage,ff8 diff --git a/riscos.mk b/riscos.mk new file mode 100644 index 0000000..729f43f --- /dev/null +++ b/riscos.mk @@ -0,0 +1,9 @@ +CC = gcc +CC_DEBUG = gcc + +PLATFORM_CFLAGS_RISCOS = -INSLibs:include -IOSLib: +PLATFORM_CFLAGS_DEBUG = -INSLibs:include -IOSLib: + +LDFLAGS_RISCOS = OSLib:o.oslib32 + +RUNIMAGE = !NSTheme/!RunImage diff --git a/riscos/dialog.c b/riscos/dialog.c new file mode 100644 index 0000000..0780992 --- /dev/null +++ b/riscos/dialog.c @@ -0,0 +1,479 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2004 James Bursa + * Copyright 2003 John M Bell + * Copyright 2004 Richard Wilson + * Copyright 2004 Andrew Timmins + */ + +#include +#include +#include +#include +#include "oslib/colourtrans.h" +#include "oslib/os.h" +#include "oslib/osfile.h" +#include "oslib/osgbpb.h" +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" +#include "nstheme/desktop/nstheme.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/options.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/utils.h" + + +osspriteop_area *theme_sprites = NULL; + +const char *theme_sprite_name[] = { + "back", "pback", + "forward", "pforward", + "stop", "pstop", + "reload", "preload", + "home", "phome", + "search", "psearch", + "history", "phistory", + "scale", "pscale", + "hotlist", "photlist", + "save", "psave", + "print", "pprint", + "create", "pcreate", + "delete", "pdelete", + "launch", "plaunch", + "open", "popen", + "expand", "pexpand", + "separator", + NULL +}; + + +wimp_w dialog_info, dialog_main, dialog_saveas, dialog_warning; + +static void ro_gui_dialog_click_main(wimp_pointer *pointer); +static void ro_gui_dialog_click_warning(wimp_pointer *pointer); +static wimp_w ro_gui_dialog_create(const char *template_name); +static wimp_window * ro_gui_dialog_load_template(const char *template_name); +static void ro_gui_dialog_main_report(void); +static unsigned int ro_gui_dialog_test_sprite(const char *name); + + +/** + * Load and create dialogs from template file. + */ + +void ro_gui_dialog_init(void) +{ + dialog_info = ro_gui_dialog_create("info"); + dialog_main = ro_gui_dialog_create("main"); + dialog_saveas = ro_gui_dialog_create("saveas"); + dialog_warning = ro_gui_dialog_create("warning"); + ro_gui_set_icon_string(dialog_main, ICON_MAIN_NAME, "\0"); + ro_gui_set_icon_string(dialog_main, ICON_MAIN_AUTHOR, "\0"); +} + + +/** + * 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; + + /* 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; +} + + +/** + * 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 */ + 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; +} + + +/** + * Open a dialog box, centered on the screen. + */ + +void ro_gui_dialog_open(wimp_w w) +{ + int screen_x, screen_y, dx, dy; + wimp_window_state open; + 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 */ + open.w = w; + error = xwimp_get_window_state(&open); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + dx = (open.visible.x1 - open.visible.x0) / 2; + dy = (open.visible.y1 - open.visible.y0) / 2; + open.visible.x0 = screen_x - dx; + open.visible.x1 = screen_x + dx; + open.visible.y0 = screen_y - dy; + open.visible.y1 = screen_y + dy; + open.next = wimp_TOP; + error = xwimp_open_window((wimp_open *) &open); + if (error) { + LOG(("xwimp_open_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + /* Set the caret position + */ + ro_gui_set_caret_first(w); +} + + + + +/** + * Handle key presses in one of the dialog boxes. + */ + +bool ro_gui_dialog_keypress(wimp_key *key) { + if (key->c == wimp_KEY_ESCAPE) { + ro_gui_dialog_close(key->w); + return true; + } else if (key->c == wimp_KEY_RETURN) { +/* if ((key->w == dialog_folder) || (key->w == dialog_entry)) { + return true; + } +*/ } + return false; +} + + +/** + * Handle clicks in one of the dialog boxes. + */ + +void ro_gui_dialog_click(wimp_pointer *pointer) +{ + if (pointer->buttons == wimp_CLICK_MENU) { + if (pointer->w == dialog_main) { + ro_gui_create_menu(main_menu, pointer->pos.x, + pointer->pos.y); + } + return; + } + + if (pointer->w == dialog_main) + ro_gui_dialog_click_main(pointer); + else if (pointer->w == dialog_warning) + ro_gui_dialog_click_warning(pointer); +} + + +/** + * Handle clicks in the main dialog. + */ + +void ro_gui_dialog_click_main(wimp_pointer *pointer) { + if (pointer->i == ICON_MAIN_BROWSER_MENU) { + ro_gui_popup_menu(colour_menu, dialog_main, + ICON_MAIN_BROWSER_MENU); + } else if (pointer->i == ICON_MAIN_HOTLIST_MENU) { + ro_gui_popup_menu(colour_menu, dialog_main, + ICON_MAIN_HOTLIST_MENU); + } else if (pointer->i == ICON_MAIN_STATUSBG_MENU) { + ro_gui_popup_menu(colour_menu, dialog_main, + ICON_MAIN_STATUSBG_MENU); + } else if (pointer->i == ICON_MAIN_STATUSFG_MENU) { + ro_gui_popup_menu(colour_menu, dialog_main, + ICON_MAIN_STATUSFG_MENU); + } else if (pointer->i == ICON_MAIN_REPORT) { + ro_gui_dialog_main_report(); + } else if (pointer->i == ICON_MAIN_REMOVE) { + if (theme_sprites) { + free(theme_sprites); + theme_sprites = NULL; + ro_gui_dialog_prepare_main(); + } + } +} + + +/** + * Handle clicks in the warning dialog. + */ + +void ro_gui_dialog_click_warning(wimp_pointer *pointer) +{ + if (pointer->i == ICON_WARNING_CONTINUE) + ro_gui_dialog_close(dialog_warning); +} + + +/** + * Close a dialog box. + */ + +void ro_gui_dialog_close(wimp_w close) { + os_error *error; + error = xwimp_close_window(close); + if (error) { + LOG(("xwimp_close_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } +} + +void ro_gui_dialog_prepare_main(void) { + ro_gui_set_icon_shaded_state(dialog_main, ICON_MAIN_REMOVE, + (theme_sprites == NULL)); + +} + +void ro_gui_dialog_main_report(void) { + char name[16]; + char name2[16]; + const char *lookup_name; + const char *pushed_name; + unsigned int i; + int j, n; + unsigned int err; + int warn_count = 0; + bool found; + int throb_frames = -1; + FILE *fp; + fp = fopen("", "w"); + if (!fp) { + warn_user("ReportError", 0); + LOG(("failed to open file '' for writing")); + return; + } + fprintf(fp, messages_get("Title")); + fprintf(fp, "\n"); + for (i = 0; i < strlen(messages_get("Title")); i++) { + fprintf(fp, "="); + } + fprintf(fp, "\n"); + if (theme_sprites) { + i = 0; + while (theme_sprite_name[i]) { + err = ro_gui_dialog_test_sprite(theme_sprite_name[i]); + if (err & 1) { + warn_count++; + lookup_name = messages_get(theme_sprite_name[i & ~1]); + if (i & 1) { + pushed_name = messages_get("pushed"); + } else { + pushed_name = ""; + } + fprintf(fp, messages_get("WarnNoSpr"), + theme_sprite_name[i], + lookup_name, pushed_name); + fprintf(fp, "\n"); + } + if (err & 2) { + warn_count++; + fprintf(fp, messages_get("WarnHighSpr"), + theme_sprite_name[i]); + fprintf(fp, "\n"); + } + if (err & 4) { + warn_count++; + fprintf(fp, messages_get("WarnAlphaSpr"), + theme_sprite_name[i]); + fprintf(fp, "\n"); + } + i++; + } + for (j = 1; j <= theme_sprites->sprite_count; j++) { + found = false; + osspriteop_return_name(osspriteop_USER_AREA, + theme_sprites, name, 16, j); + if (strncmp(name, "throbber", 8) == 0) { + n = atoi(name + 8); + sprintf(name2, "throbber%i", n); + if (strcmp(name, name2) == 0) { + found = true; + throb_frames = n; + } + } else { + i = 0; + while (!found && theme_sprite_name[i]) { + if (strcmp(name, theme_sprite_name[i]) == 0) { + found = true; + } + i++; + } + } + + if (!found) { + warn_count++; + fprintf(fp, messages_get("WarnExtraSpr"), + name); + fprintf(fp, "\n"); + err = ro_gui_dialog_test_sprite(name); + if (err & 2) { + warn_count++; + fprintf(fp, messages_get("WarnHighSpr"), + name); + fprintf(fp, "\n"); + } + if (err & 4) { + warn_count++; + fprintf(fp, messages_get("WarnAlphaSpr"), + name); + fprintf(fp, "\n"); + } + } + } + if (throb_frames == -1) { + fprintf(fp, messages_get("WarnNoThrob")); + fprintf(fp, "\n"); + + } else { + for (j = 0; j < throb_frames; j++) { + sprintf(name, "throbber%i", j); + err = ro_gui_dialog_test_sprite(name); + if (err & 1) { + warn_count++; + fprintf(fp, messages_get("WarnMissThrob"), + name); + fprintf(fp, "\n"); + } + if (err & 2) { + warn_count++; + fprintf(fp, messages_get("WarnHighSpr"), + name); + fprintf(fp, "\n"); + } + if (err & 4) { + warn_count++; + fprintf(fp, messages_get("WarnAlphaSpr"), + name); + fprintf(fp, "\n"); + } + } + } + + } else { + warn_count++; + fprintf(fp, messages_get("WarnNoFile")); + fprintf(fp, "\n"); + } + if (warn_count > 0) { + fprintf(fp, "\n"); + fprintf(fp, messages_get("CompleteErr"), warn_count); + fprintf(fp, "\n"); + } else { + fprintf(fp, messages_get("CompleteOK")); + fprintf(fp, "\n"); + } + + fclose(fp); + xosfile_set_type("", 0xfff); + xos_cli("Filer_Run "); +} + +unsigned int ro_gui_dialog_test_sprite(const char *name) { + unsigned int result = 0; + int var_val; + os_coord dimensions; + os_mode mode; + os_error *error; + error = xosspriteop_read_sprite_info(osspriteop_USER_AREA, + theme_sprites, (osspriteop_id)name, + &dimensions.x, &dimensions.y, 0, &mode); + if (error) return 1; + if (((unsigned int)mode) & osspriteop_ALPHA_MASK) result |= 4; + error = xos_read_mode_variable(mode, os_MODEVAR_LOG2_BPP, + &var_val, 0); + if (error) { + LOG(("xos_read_mode_variable: 0x%x: %s", + error->errnum, error->errmess)); + } else { + if (var_val > 3) result |= 2; + } + return result; +} diff --git a/riscos/gui.c b/riscos/gui.c new file mode 100644 index 0000000..be5dae3 --- /dev/null +++ b/riscos/gui.c @@ -0,0 +1,608 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2004 James Bursa + * Copyright 2003 John M Bell + * Copyright 2004 Richard Wilson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "oslib/font.h" +#include "oslib/help.h" +#include "oslib/hourglass.h" +#include "oslib/inetsuite.h" +#include "oslib/os.h" +#include "oslib/osbyte.h" +#include "oslib/osfile.h" +#include "oslib/osfscontrol.h" +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" +#include "oslib/wimpspriteop.h" +#include "oslib/uri.h" +#include "nstheme/desktop/gui.h" +#include "nstheme/desktop/nstheme.h" +#include "nstheme/desktop/options.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/help.h" +#include "nstheme/riscos/options.h" +//#include "nstheme/riscos/theme.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/utils.h" + +const char *__dynamic_da_name = "NSTheme"; /**< For UnixLib. */ +int __feature_imagefs_is_file = 1; /**< For UnixLib. */ +/* default filename handling */ +int __riscosify_control = __RISCOSIFY_NO_SUFFIX | + __RISCOSIFY_NO_REVERSE_SUFFIX; + +char *NSTHEME_DIR; + +wimp_t task_handle; /**< RISC OS wimp task handle. */ +static clock_t gui_last_poll; /**< Time of last wimp_poll. */ + +/** Accepted wimp user messages. */ +static wimp_MESSAGE_LIST(33) task_messages = { { + message_HELP_REQUEST, + message_DATA_SAVE, + message_DATA_SAVE_ACK, + message_DATA_LOAD, + message_DATA_LOAD_ACK, + message_MENU_WARNING, + 0 +} }; +struct ro_gui_poll_block { + wimp_event_no event; + wimp_block *block; + struct ro_gui_poll_block *next; +}; +struct ro_gui_poll_block *ro_gui_poll_queued_blocks = 0; + + +static void ro_gui_choose_language(void); +static void ro_gui_icon_bar_create(void); +static void ro_gui_handle_event(wimp_event_no event, wimp_block *block); +static void ro_gui_poll_queue(wimp_event_no event, wimp_block *block); +static void ro_gui_open_window_request(wimp_open *open); +static void ro_gui_close_window_request(wimp_close *close); +static void ro_gui_mouse_click(wimp_pointer *pointer); +static void ro_gui_icon_bar_click(wimp_pointer *pointer); +static void ro_gui_drag_end(wimp_dragged *drag); +static void ro_gui_keypress(wimp_key *key); +static void ro_gui_user_message(wimp_event_no event, wimp_message *message); +static void ro_msg_dataload(wimp_message *block); +static void ro_msg_datasave_ack(wimp_message *message); + + +/** + * Initialise the gui (RISC OS specific part). + */ + +void gui_init(void) { + char path[40]; + os_error *error; + int length; + + xhourglass_start(1); + + options_read("Choices:NSTheme.Choices"); + ro_gui_choose_language(); + + NSTHEME_DIR = getenv("NSTheme$Dir"); + if ((length = snprintf(path, sizeof(path), + ".Resources.%s.Messages", + option_language)) < 0 || length >= (int)sizeof(path)) + die("Failed to locate Messages resource."); + messages_load(path); + + /* Totally pedantic, but base the taskname on the build options. + */ + error = xwimp_initialise(wimp_VERSION_RO38, "NSTheme", + (const wimp_message_list *) &task_messages, 0, + &task_handle); + if (error) { + LOG(("xwimp_initialise failed: 0x%x: %s", + error->errnum, error->errmess)); + die(error->errmess); + } + + /* Open the templates + */ + if ((length = snprintf(path, sizeof(path), + ".Resources.%s.Templates", + option_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); + } + ro_gui_dialog_init(); + ro_gui_menus_init(); + xwimp_close_template(); + + ro_gui_icon_bar_create(); +} + +/** + * Determine the language to use. + * + * RISC OS has no standard way of determining which language the user prefers. + * We have to guess from the 'Country' setting. + */ + +void ro_gui_choose_language(void) +{ + char path[40]; + const char *lang; + int country; + os_error *error; + + /* if option_language exists and is valid, use that */ + if (option_language) { + if (2 < strlen(option_language)) + option_language[2] = 0; + sprintf(path, ".Resources.%s", option_language); + if (is_dir(path)) return; + free(option_language); + option_language = 0; + } + + /* 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 6: /* France */ + case 18: /* Canada2 (French Canada?) */ + lang = "fr"; + break; + default: + lang = "en"; + break; + } + sprintf(path, ".Resources.%s", lang); + if (is_dir(path)) + option_language = strdup(lang); + else + option_language = strdup("en"); + assert(option_language); +} + + +/** + * Create an iconbar icon. + */ + +void ro_gui_icon_bar_create(void) +{ + wimp_icon_create icon = { + wimp_ICON_BAR_RIGHT, + { { 0, 0, 68, 68 }, + wimp_ICON_SPRITE | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED | + (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT), + { "!nstheme" } } }; + wimp_create_icon(&icon); +} + + + +/** + * Close down the gui (RISC OS). + */ + +void gui_exit(void) { + xosfile_create_dir(".NSTheme", 0); + options_write(".NSTheme.Choices"); + xwimp_close_down(task_handle); + xhourglass_off(); +} + + +/** + * Poll the OS for events (RISC OS). + * + * \param active return as soon as possible + */ + +void gui_poll(void) +{ + wimp_event_no event; + wimp_block block; + const wimp_poll_flags mask = wimp_MASK_LOSE | wimp_MASK_GAIN; + + /* Process queued events. */ + while (ro_gui_poll_queued_blocks) { + struct ro_gui_poll_block *next; + ro_gui_handle_event(ro_gui_poll_queued_blocks->event, + ro_gui_poll_queued_blocks->block); + next = ro_gui_poll_queued_blocks->next; + free(ro_gui_poll_queued_blocks->block); + free(ro_gui_poll_queued_blocks); + ro_gui_poll_queued_blocks = next; + } + + /* Poll wimp. */ + xhourglass_off(); + event = wimp_poll(wimp_MASK_NULL | mask, &block, 0); + xhourglass_on(); + gui_last_poll = clock(); + ro_gui_handle_event(event, &block); +} + + +/** + * Process a Wimp_Poll event. + * + * \param event wimp event number + * \param block parameter block + */ + +void ro_gui_handle_event(wimp_event_no event, wimp_block *block) +{ + switch (event) { + 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_MOUSE_CLICK: + ro_gui_mouse_click(&block->pointer); + break; + + case wimp_USER_DRAG_BOX: + ro_gui_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; + + case wimp_USER_MESSAGE: + case wimp_USER_MESSAGE_RECORDED: + case wimp_USER_MESSAGE_ACKNOWLEDGE: + ro_gui_user_message(event, &(block->message)); + break; + } +} + + +/** + * Check for important events and yield CPU (RISC OS). + * + * Required on RISC OS for cooperative multitasking. + */ + +void gui_multitask(void) +{ + wimp_event_no event; + wimp_block block; + + if (clock() < gui_last_poll + 10) + return; + + xhourglass_off(); + event = wimp_poll(wimp_MASK_LOSE | wimp_MASK_GAIN, &block, 0); + xhourglass_on(); + gui_last_poll = clock(); + + switch (event) { + case wimp_CLOSE_WINDOW_REQUEST: + /* \todo close the window, and destroy content + * or abort loading of content */ + break; + + case wimp_KEY_PRESSED: + case wimp_MENU_SELECTION: + ro_gui_poll_queue(event, &block); + break; + + default: + ro_gui_handle_event(event, &block); + break; + } +} + + +/** + * Add a wimp_block to the queue for later handling. + */ + +void ro_gui_poll_queue(wimp_event_no event, wimp_block *block) +{ + struct ro_gui_poll_block *q = + calloc(1, sizeof(struct ro_gui_poll_block)); + if (!q) return; + q->event = event; + q->block = calloc(1, sizeof(*block)); + if (!q->block) { + free(q); + return; + } + memcpy(q->block, block, sizeof(*block)); + q->next = NULL; + + if (ro_gui_poll_queued_blocks == NULL) { + ro_gui_poll_queued_blocks = q; + return; + } else { + struct ro_gui_poll_block *current = + ro_gui_poll_queued_blocks; + while (current->next != NULL) + current = current->next; + current->next = q; + } + return; +} + + +/** + * Handle Open_Window_Request events. + */ + +void ro_gui_open_window_request(wimp_open *open) { + os_error *error; + error = xwimp_open_window(open); + if (error) { + LOG(("xwimp_open_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } +} + + +/** + * Handle Close_Window_Request events. + */ + +void ro_gui_close_window_request(wimp_close *close) { + ro_gui_dialog_close(close->w); +} + + +/** + * Handle Mouse_Click events. + */ +void ro_gui_mouse_click(wimp_pointer *pointer) { + if (pointer->w == wimp_ICON_BAR) { + ro_gui_icon_bar_click(pointer); + } else if (pointer->w == dialog_saveas) { + ro_gui_save_click(pointer); + } else { + ro_gui_dialog_click(pointer); + } +} + +/** + * Handle Mouse_Click events on the iconbar icon. + */ + +void ro_gui_icon_bar_click(wimp_pointer *pointer) +{ + if (pointer->buttons == wimp_CLICK_MENU) { + ro_gui_create_menu(iconbar_menu, pointer->pos.x, + 96 + iconbar_menu_height); + } else if (pointer->buttons == wimp_CLICK_SELECT) { + ro_gui_dialog_prepare_main(); + ro_gui_open_window_centre(NULL, dialog_main); + ro_gui_set_caret_first(dialog_main); + } +} + + +/** + * Handle User_Drag_Box events. + */ + +void ro_gui_drag_end(wimp_dragged *drag) { + ro_gui_save_drag_end(drag); +} + + +/** + * Handle Key_Pressed events. + */ + +void ro_gui_keypress(wimp_key *key) { + bool handled = false; + os_error *error; + + if (key->c == wimp_KEY_F1) { + xos_cli("Filer_Run .!Help"); + } + + if (key->w == dialog_saveas) { +// handled = ro_gui_saveas_keypress(key->c); + } else { + handled = ro_gui_dialog_keypress(key); + } + + if (!handled) { + error = xwimp_process_key(key->c); + if (error) { + LOG(("xwimp_process_key: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + } +} + + +/** + * Handle the three User_Message events. + */ + +void ro_gui_user_message(wimp_event_no event, wimp_message *message) +{ + switch (message->action) { + case message_HELP_REQUEST: + ro_gui_interactive_help_request(message); + break; + + case message_DATA_SAVE_ACK: + ro_msg_datasave_ack(message); + break; + + case message_DATA_LOAD: + if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) { + } + else + ro_msg_dataload(message); + break; + + case message_DATA_LOAD_ACK: + break; + + case message_MENU_WARNING: + ro_gui_menu_warning((wimp_message_menu_warning *) + &message->data); + break; + + case message_QUIT: + application_quit = true; + break; + } +} + + +/** + * Handle Message_DataLoad (file dragged in). + */ + +void ro_msg_dataload(wimp_message *message) { + os_error *error; + osspriteop_area *area; + bool success = false; + char *filename = message->data.data_xfer.file_name; + int file_type = message->data.data_xfer.file_type; + if ((file_type == 0xff9) && (message->data.data_xfer.w == dialog_main)) { + area = ro_gui_load_sprite_file(filename); + if (area) { + success = true; + if (theme_sprites) free(theme_sprites); + theme_sprites = area; + ro_gui_dialog_prepare_main(); + if (sprite_filename) { + free(sprite_filename); + sprite_filename = NULL; + } + } + } else { + success = ro_gui_load_theme(filename); + if (success) { + ro_gui_dialog_prepare_main(); + ro_gui_open_window_centre(NULL, dialog_main); + ro_gui_set_caret_first(dialog_main); + } + } + + if (!success) return; + message->action = message_DATA_LOAD_ACK; + message->your_ref = message->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender); + if (error) { + LOG(("xwimp_send_message: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } +} + + +/** + * Handle Message_DataSaveAck. + */ + +void ro_msg_datasave_ack(wimp_message *message) { + ro_gui_save_datasave_ack(message); +} + + +/** + * Find screen size in OS units. + */ + +void ro_gui_screen_size(int *width, int *height) +{ + int xeig_factor, yeig_factor, xwind_limit, ywind_limit; + + os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XEIG_FACTOR, &xeig_factor); + os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YEIG_FACTOR, &yeig_factor); + os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XWIND_LIMIT, &xwind_limit); + os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YWIND_LIMIT, &ywind_limit); + *width = (xwind_limit + 1) << xeig_factor; + *height = (ywind_limit + 1) << yeig_factor; +} + + +/** + * Display a warning for a serious problem (eg memory exhaustion). + * + * \param warning message key for warning message + * \param detail additional message, or 0 + */ + +void warn_user(const char *warning, const char *detail) +{ + static char warn_buffer[300]; + + LOG(("%s %s", warning, detail)); + 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); + xwimp_set_icon_state(dialog_warning, ICON_WARNING_HELP, + wimp_ICON_DELETED, wimp_ICON_DELETED); + ro_gui_dialog_open(dialog_warning); + xos_bell(); +} + + +/** + * Display an error and exit. + * + * Should only be used during initialisation. + */ + +void die(const char *error) +{ + os_error warn_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, + "NSTheme", "!nstheme", + (osspriteop_area *) 1, 0, 0); + exit(EXIT_FAILURE); +} diff --git a/riscos/gui.h b/riscos/gui.h new file mode 100644 index 0000000..54b312c --- /dev/null +++ b/riscos/gui.h @@ -0,0 +1,97 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2004 James Bursa + * Copyright 2004 Andrew Timmins + */ + +#ifndef _NETSURF_RISCOS_GUI_H_ +#define _NETSURF_RISCOS_GUI_H_ + +#include +#include +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" +#include "nstheme/desktop/nstheme.h" +#include "nstheme/desktop/gui.h" +#include "nstheme/desktop/options.h" + +#define THEMES_DIR ".Themes" + +extern char *theme_filename; +extern char *sprite_filename; +extern osspriteop_area *theme_sprites; +extern wimp_w dialog_info, dialog_main, dialog_saveas, dialog_warning; +extern wimp_menu *iconbar_menu, *main_menu, *colour_menu; +extern int iconbar_menu_height; +extern wimp_menu *current_menu; + +struct theme_file_header { + unsigned int magic_value; + unsigned int parser_version; + char name[32]; + char author[64]; + char browser_bg; + char hotlist_bg; + char status_bg; + char status_fg; + char throbber_left; + char future_expansion_1; + char future_expansion_2; + char future_expansion_3; + unsigned int compressed_sprite_size; + unsigned int decompressed_sprite_size; +}; + +/* in gui.c */ +void ro_gui_screen_size(int *width, int *height); +//void ro_gui_drag_box_start(wimp_pointer *pointer); + +/* in menus.c */ +void ro_gui_menus_init(void); +void ro_gui_create_menu(wimp_menu* menu, int x, int y); +void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i); +void ro_gui_menu_selection(wimp_selection* selection); +void ro_gui_menu_warning(wimp_message_menu_warning *warning); + +/* in dialog.c */ +void ro_gui_dialog_init(void); +void ro_gui_dialog_open(wimp_w w); +void ro_gui_dialog_close(wimp_w close); +void ro_gui_dialog_click(wimp_pointer *pointer); +bool ro_gui_dialog_keypress(wimp_key *key); +void ro_gui_dialog_prepare_main(void); + +/* in save.c */ +void ro_gui_save_open(int save_type, int x, int y); +void ro_gui_save_click(wimp_pointer *pointer); +void ro_gui_save_drag_end(wimp_dragged *drag); +void ro_gui_save_datasave_ack(wimp_message *message); +bool ro_gui_load_theme(char *path); + +#define ICON_WARNING_MESSAGE 0 +#define ICON_WARNING_CONTINUE 1 +#define ICON_WARNING_HELP 2 + +#define ICON_MAIN_NAME 3 +#define ICON_MAIN_AUTHOR 5 +#define ICON_MAIN_THROBBER_LEFT 8 +#define ICON_MAIN_REPORT 11 +#define ICON_MAIN_REMOVE 12 +#define ICON_MAIN_BROWSER_COLOUR 16 +#define ICON_MAIN_BROWSER_MENU 17 +#define ICON_MAIN_HOTLIST_COLOUR 19 +#define ICON_MAIN_HOTLIST_MENU 20 +#define ICON_MAIN_STATUSBG_COLOUR 22 +#define ICON_MAIN_STATUSBG_MENU 23 +#define ICON_MAIN_STATUSFG_COLOUR 25 +#define ICON_MAIN_STATUSFG_MENU 26 + +#define ICON_SAVE_ICON 0 +#define ICON_SAVE_PATH 1 +#define ICON_SAVE_OK 2 +#define ICON_SAVE_CANCEL 3 + +#endif diff --git a/riscos/help.c b/riscos/help.c new file mode 100644 index 0000000..62bfd8a --- /dev/null +++ b/riscos/help.c @@ -0,0 +1,257 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * Interactive help (implementation). + */ + +#include +#include +#include +#include "oslib/help.h" +#include "oslib/os.h" +#include "oslib/taskmanager.h" +#include "oslib/wimp.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/help.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/log.h" + + +/* Recognised help keys + ==================== + + HelpIconbar Iconbar (no icon suffix is used) + + HelpAppInfo Application info window + HelpMain Main application window + HelpSaveAs Save as window + HelpWarning Warning window + + HelpIconMenu Iconbar menu + HelpMainMenu Main application menu + + The prefixes are followed by either the icon number (eg 'HelpToolbar7'), or a series + of numbers representing the menu structure (eg 'HelpBrowserMenu3-1-2'). + If '' is not available, then simply '' is then used. For example + if 'HelpToolbar7' is not available then 'HelpToolbar' is then tried. + + If an item is greyed out then a suffix of 'g' is added (eg 'HelpToolbar7g'). For this to + work, windows must have bit 4 of the window flag byte set and the user must be running + RISC OS 5.03 or greater. +*/ + +static void ro_gui_interactive_help_broadcast(wimp_message *message, char *token); +static os_t help_time = 0; + +/** + * Attempts to process an interactive help message request + * + * \param message the request message + */ +void ro_gui_interactive_help_request(wimp_message *message) { + char message_token[32]; + char menu_buffer[4]; + wimp_selection menu_tree; + help_full_message_request *message_data; + wimp_w window; + wimp_i icon; + unsigned int index; + bool greyed = false; + wimp_menu *test_menu; + + /* Ensure we have a help request + */ + if ((!message) || (message->action != message_HELP_REQUEST)) return; + + /* Remember the time of the request + */ + xos_read_monotonic_time(&help_time); + + /* Initialise the basic token to a null byte + */ + message_token[0] = 0x00; + + /* Get the message data + */ + message_data = (help_full_message_request *)message; + window = message_data->w; + icon = message_data->i; + + /* Do the basic window checks + */ + if (window == (wimp_w)-2) { + sprintf(message_token, "HelpIconbar"); + } else if (window == dialog_info) { + sprintf(message_token, "HelpAppInfo%i", (int)icon); + } else if (window == dialog_main) { + sprintf(message_token, "HelpMain%i", (int)icon); + } else if (window == dialog_saveas) { + sprintf(message_token, "HelpSaveAs%i", (int)icon); + } else if (window == dialog_warning) { + sprintf(message_token, "HelpWarning%i", (int)icon); + } + + /* If we've managed to find something so far then we broadcast it + */ + if (message_token[0] != 0x00) { + /* Check to see if we are greyed out + */ + if ((icon >= 0) && (ro_gui_get_icon_shaded_state(window, icon))) { + strcat(message_token, "g"); + } + + /* Broadcast out message + */ + ro_gui_interactive_help_broadcast(message, &message_token[0]); + return; + } + + /* If we are not on an icon, we can't be in a menu (which stops separators + giving help for their parent) so we abort. You don't even want to think + about the awful hack I was considering before I realised this... + */ + if (icon == (wimp_i)-1) return; + + /* As a last resort, check for menu help. + */ + if (xwimp_get_menu_state((wimp_menu_state_flags)1, + &menu_tree, + window, icon)) return; + if (menu_tree.items[0] == -1) return; + + /* Set the prefix + */ + if (current_menu == iconbar_menu) { + sprintf(message_token, "HelpIconMenu"); + } else if (current_menu == main_menu) { + sprintf(message_token, "HelpMainMenu"); + } else { + return; + } + + /* Decode the menu + */ + index = 0; + test_menu = current_menu; + while (menu_tree.items[index] != -1) { + /* Check if we're greyed out + */ + greyed |= test_menu->entries[menu_tree.items[index]].icon_flags & wimp_ICON_SHADED; + test_menu = test_menu->entries[menu_tree.items[index]].sub_menu; + + /* Continue adding the entries + */ + if (index == 0) { + sprintf(menu_buffer, "%i", menu_tree.items[index]); + } else { + sprintf(menu_buffer, "-%i", menu_tree.items[index]); + } + strcat(message_token, menu_buffer); + index++; + } + if (greyed) strcat(message_token, "g"); + + /* Finally, broadcast the menu help + */ + ro_gui_interactive_help_broadcast(message, &message_token[0]); +} + + +/** + * Broadcasts a help reply + * + * \param message the original request message + * \param token the token to look up + */ +static void ro_gui_interactive_help_broadcast(wimp_message *message, char *token) { + const char *translated_token; + help_full_message_reply *reply; + char *base_token; + + /* Start off with an empty reply + */ + reply = (help_full_message_reply *)message; + reply->reply[0] = '\0'; + + /* Check if the message exists + */ + translated_token = messages_get(token); + if (translated_token == token) { + /* We must never provide default help for a 'g' suffix. + */ + if (token[strlen(token) - 1] != 'g') { + /* Find the key from the token. + */ + base_token = token; + while (base_token[0] != 0x00) { + if ((base_token[0] == '-') || + ((base_token[0] >= '0') && (base_token[0] <= '9'))) { + base_token[0] = 0x00; + } else { + ++base_token; + } + } + + /* Check if the base key exists and use an empty string if not + */ + translated_token = messages_get(token); + } + } + + + /* Copy our message string + */ + if (translated_token != token) { + reply->reply[235] = 0; + strncpy(reply->reply, translated_token, 235); + } + + /* Broadcast the help reply + */ + reply->size = 256; + reply->action = message_HELP_REPLY; + reply->your_ref = reply->my_ref; + wimp_send_message(wimp_USER_MESSAGE, (wimp_message *)reply, reply->sender); +} + + +/** + * Checks if interactive help is running + * + * \return non-zero if interactive help is available, or 0 if not available + */ +int ro_gui_interactive_help_available() { + taskmanager_task task; + int context = 0; + char *end; + os_t time; + + /* Check if we've received a help request in the last 0.5s to test for generic + interactive help applications + */ + xos_read_monotonic_time(&time); + if ((help_time + 50) > time) return true; + + /* Attempt to find the task 'Help' + */ + do { + if (xtaskmanager_enumerate_tasks(context, &task, sizeof(taskmanager_task), + &context, &end)) return 0; + + /* We can't just use strcmp due to string termination issues. + */ + if (strncmp(task.name, "Help", 4) == 0) { + if (task.name[4] < 32) return true; + } + } while (context >= 0); + + /* Return failure + */ + return 0; +} diff --git a/riscos/help.h b/riscos/help.h new file mode 100644 index 0000000..444dec7 --- /dev/null +++ b/riscos/help.h @@ -0,0 +1,20 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * Interactive help (interface). + */ + +#ifndef _NETSURF_RISCOS_HELP_H_ +#define _NETSURF_RISCOS_HELP_H_ + +#include "oslib/wimp.h" + +void ro_gui_interactive_help_request(wimp_message *message); +int ro_gui_interactive_help_available(void); + +#endif diff --git a/riscos/menus.c b/riscos/menus.c new file mode 100644 index 0000000..f1711a3 --- /dev/null +++ b/riscos/menus.c @@ -0,0 +1,272 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2004 James Bursa + * Copyright 2003 John M Bell + * Copyright 2004 Richard Wilson + */ + +/** \file + * Menu creation and handling (implementation). + */ + +#include +#include +#include "oslib/os.h" +#include "oslib/osgbpb.h" +#include "oslib/wimp.h" +#include "nstheme/desktop/gui.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/help.h" +#include "nstheme/riscos/options.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/utils.h" + + +static void translate_menu(wimp_menu *menu); + + +wimp_menu *current_menu; +wimp_i menu_icon; + +/* Default menu item flags +*/ +#define COLOUR_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \ + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT)) +#define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \ + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | \ + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT)) + + +/* Iconbar menu +*/ +static wimp_MENU(4) ibar_menu = { + { "NSTheme" }, 7,2,7,0, 200, 44, 0, + { + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Info" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "AppHelp" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Quit" } } + } +}; +int iconbar_menu_height = 3 * 44; +wimp_menu *iconbar_menu = (wimp_menu *)&ibar_menu; + + +/* Colour menu +*/ +static wimp_MENU(16) col_menu = { + { "Colour" }, 7,2,7,0, 200, 44, 0, + { + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_MID_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_MID_DARK_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_DARK_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_VERY_DARK_GREY << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_BLACK << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_DARK_BLUE << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_YELLOW << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_LIGHT_GREEN << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_RED << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_CREAM << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_DARK_GREEN << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { 0, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_ORANGE << wimp_ICON_BG_COLOUR_SHIFT), { "" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, COLOUR_FLAGS | + (wimp_COLOUR_LIGHT_BLUE << wimp_ICON_BG_COLOUR_SHIFT), { "" } } + } +}; +wimp_menu *colour_menu = (wimp_menu *)&col_menu; + +/* Main browser menu +*/ +static wimp_MENU(3) menu = { + { "NSTheme" }, 7,2,7,0, 200, 44, 0, + { + { wimp_MENU_GIVE_WARNING, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "SaveAs" } }, + { wimp_MENU_GIVE_WARNING, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Export" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "AppHelp" } } + } +}; +wimp_menu *main_menu = (wimp_menu *) &menu; + + +/** + * Create menu structures. + */ + +void ro_gui_menus_init(void) +{ + translate_menu(iconbar_menu); + translate_menu(main_menu); + translate_menu(colour_menu); + + iconbar_menu->entries[0].sub_menu = (wimp_menu *)dialog_info; + main_menu->entries[0].sub_menu = (wimp_menu *)dialog_saveas; + main_menu->entries[1].sub_menu = (wimp_menu *)dialog_saveas; +} + + +/** + * Replace text in a menu with message values. + */ + +void translate_menu(wimp_menu *menu) +{ + unsigned int i = 0; + const char *indirected_text; + + /* We can't just blindly set something as indirected as if we use + the fallback messages text (ie the pointer we gave), we overwrite + this data when setting the pointer to the indirected text we + already had. + */ + indirected_text = messages_get(menu->title_data.text); + if (indirected_text != menu->title_data.text) { + menu->title_data.indirected_text.text = indirected_text; + menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; + + } + + /* items */ + do { + indirected_text = messages_get(menu->entries[i].data.text); + if (indirected_text != menu->entries[i].data.text) { + menu->entries[i].icon_flags |= wimp_ICON_INDIRECTED; + menu->entries[i].data.indirected_text.text = indirected_text; + menu->entries[i].data.indirected_text.validation = 0; + menu->entries[i].data.indirected_text.size = strlen(indirected_text) + 1; + } + i++; + } while ((menu->entries[i - 1].menu_flags & wimp_MENU_LAST) == 0); +} + + +/** + * Display a menu. + */ + +void ro_gui_create_menu(wimp_menu *menu, int x, int y) { + os_error *error; + current_menu = menu; + int colour; + + if (menu == colour_menu) { + colour = ro_gui_get_icon_background_colour(dialog_main, menu_icon - 1); + for (int i = 0; i < 16; i++) { + if (i == colour) { + colour_menu->entries[i].menu_flags |= wimp_MENU_TICKED; + } else { + colour_menu->entries[i].menu_flags &= ~wimp_MENU_TICKED; + } + } + } else if (menu == main_menu) { + if (theme_sprites) { + main_menu->entries[1].icon_flags &= ~wimp_ICON_SHADED; + } else { + main_menu->entries[1].icon_flags |= wimp_ICON_SHADED; + } + } + + error = xwimp_create_menu(menu, x - 64, y); + if (error) { + LOG(("xwimp_create_menu: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MenuError", error->errmess); + } +} + + +/** + * Display a pop-up menu next to the specified icon. + */ + +void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i) { + wimp_window_state state; + wimp_icon_state icon_state; + state.w = w; + icon_state.w = w; + icon_state.i = i; + wimp_get_window_state(&state); + wimp_get_icon_state(&icon_state); + menu_icon = i; + ro_gui_create_menu(menu, + state.visible.x0 + icon_state.icon.extent.x1 + 64, + state.visible.y1 + icon_state.icon.extent.y1); +} + + +/** + * Handle menu selection. + */ + +void ro_gui_menu_selection(wimp_selection *selection) { + wimp_pointer pointer; + + wimp_get_pointer_info(&pointer); + + if (current_menu == iconbar_menu) { + switch (selection->items[0]) { + case 0: /* Info */ + ro_gui_create_menu((wimp_menu *) dialog_info, + pointer.pos.x, pointer.pos.y); + break; + case 1: /* Help */ + xos_cli("Filer_Run .!Help"); + break; + case 2: /* Quit */ + application_quit = true; + break; + } + + } else if (current_menu == main_menu) { + switch (selection->items[0]) { + case 2: /* Help */ + xos_cli("Filer_Run .!Help"); + break; + } + } else if (current_menu == colour_menu) { + ro_gui_set_icon_background_colour(dialog_main, menu_icon - 1, + selection->items[0]); + } + + if (pointer.buttons == wimp_CLICK_ADJUST) { + ro_gui_create_menu(current_menu, 0, 0); + } + +} + +/** + * Handle Message_MenuWarning. + */ + +void ro_gui_menu_warning(wimp_message_menu_warning *warning) { + if (current_menu != main_menu) return; + switch (warning->selection.items[0]) { + case 0: + ro_gui_save_open(1, warning->pos.x, warning->pos.y); + break; + case 1: + ro_gui_save_open(2, warning->pos.x, warning->pos.y); + break; + } +} diff --git a/riscos/options.h b/riscos/options.h new file mode 100644 index 0000000..b003da1 --- /dev/null +++ b/riscos/options.h @@ -0,0 +1,24 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * RISC OS specific options. + */ + +#ifndef _NETSURF_RISCOS_OPTIONS_H_ +#define _NETSURF_RISCOS_OPTIONS_H_ + +#include "netsurf/desktop/options.h" + +extern char *option_language; + +#define EXTRA_OPTION_DEFINE \ +char *option_language = 0;\ + +#define EXTRA_OPTION_TABLE \ +{ "language", OPTION_STRING, &option_language } +#endif diff --git a/riscos/save.c b/riscos/save.c new file mode 100644 index 0000000..c6bc06f --- /dev/null +++ b/riscos/save.c @@ -0,0 +1,554 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 James Bursa + */ + +/** \file + * Save dialog and drag and drop saving (implementation). + */ + +#include +#include +#include +#include +#include +#include +#include "oslib/dragasprite.h" +#include "oslib/osgbpb.h" +#include "oslib/osfile.h" +#include "oslib/osfind.h" +#include "oslib/osspriteop.h" +#include "oslib/squash.h" +#include "oslib/wimp.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/utils.h" + +#define SAVE_THEME 1 +#define SAVE_SPRITES 2 +static int gui_save_current_type = 0; +static char *reset_filename; +static unsigned int gui_save_filetype; + +char *theme_filename = NULL; +char *sprite_filename = NULL; +static bool close_menu = true; + +static void ro_gui_drag_icon(wimp_pointer *pointer); +static bool ro_gui_save(char *path); +static bool ro_gui_save_theme(char *path); +static bool ro_gui_save_sprites(char *path); + +/** + * Prepares the save box to reflect gui_save_type and a content, and + * opens it. + * + * \param save_type type of save + * \param c content to save + * \param sub_menu open dialog as a sub menu, otherwise persistent + * \param x x position, for sub_menu true only + * \param y y position, for sub_menu true only + * \param parent parent window for persistent box, for sub_menu false only + */ + +void ro_gui_save_open(int save_type, int x, int y) +{ + char icon_buf[20]; + const char *icon = icon_buf; + os_error *error; + + gui_save_current_type = save_type; + if (save_type == SAVE_THEME) { + if (theme_filename == NULL) { + theme_filename = malloc(6); + if (!theme_filename) { + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + return; + } + sprintf(theme_filename, "Theme"); + } + gui_save_filetype = 0xffd; + ro_gui_set_window_title(dialog_saveas, messages_get("SaveTitle")); + ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_PATH, theme_filename); + reset_filename = theme_filename; + } else { + if (sprite_filename == NULL) { + sprite_filename = malloc(8); + if (!sprite_filename) { + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + return; + } + sprintf(sprite_filename, "Sprites"); + } + gui_save_filetype = 0xff9; + ro_gui_set_window_title(dialog_saveas, messages_get("ExportTitle")); + ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_PATH, sprite_filename); + reset_filename = sprite_filename; + } + + + /* icon */ + sprintf(icon_buf, "file_%.3x", gui_save_filetype); + ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_ICON, icon); + + /* open sub menu or persistent dialog */ + error = xwimp_create_sub_menu((wimp_menu *) dialog_saveas, + x, y); + if (error) { + LOG(("xwimp_create_sub_menu: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MenuError", error->errmess); + } +} + + +/** + * Handle clicks in the save dialog. + */ + +void ro_gui_save_click(wimp_pointer *pointer) +{ + switch (pointer->i) { + case ICON_SAVE_OK: + close_menu = (pointer->buttons == wimp_CLICK_SELECT); + ro_gui_save(ro_gui_get_icon_string(dialog_saveas, ICON_SAVE_PATH)); + if (pointer->buttons == wimp_CLICK_SELECT) { + xwimp_create_menu((wimp_menu *)-1, 0, 0); + ro_gui_dialog_close(pointer->w); + } + break; + case ICON_SAVE_CANCEL: + if (pointer->buttons == wimp_CLICK_SELECT) { + xwimp_create_menu((wimp_menu *)-1, 0, 0); + ro_gui_dialog_close(pointer->w); + } else if (pointer->buttons == wimp_CLICK_ADJUST) { + ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_PATH, reset_filename); + } + break; + case ICON_SAVE_ICON: + if (pointer->buttons == wimp_DRAG_SELECT) { + ro_gui_drag_icon(pointer); + } + break; + } +} + + +/** + * Start drag of icon under the pointer. + */ + +void ro_gui_drag_icon(wimp_pointer *pointer) +{ + char *sprite; + os_box box = { pointer->pos.x - 34, pointer->pos.y - 34, + pointer->pos.x + 34, pointer->pos.y + 34 }; + os_error *error; + + if (pointer->i == -1) + return; + + sprite = ro_gui_get_icon_string(pointer->w, pointer->i); + + error = xdragasprite_start(dragasprite_HPOS_CENTRE | + dragasprite_VPOS_CENTRE | + dragasprite_BOUND_POINTER | + dragasprite_DROP_SHADOW, + (osspriteop_area *) 1, sprite, &box, 0); + if (error) { + LOG(("xdragasprite_start: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("DragError", error->errmess); + } +} + + +/** + * Handle User_Drag_Box event for a drag from the save dialog. + */ + +void ro_gui_save_drag_end(wimp_dragged *drag) +{ + char *name; + char *dot; + wimp_pointer pointer; + wimp_message message; + + wimp_get_pointer_info(&pointer); + + name = ro_gui_get_icon_string(dialog_saveas, ICON_SAVE_PATH); + dot = strrchr(name, '.'); + if (dot) + name = dot + 1; + + 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 = 1000; + message.data.data_xfer.file_type = gui_save_filetype; + strncpy(message.data.data_xfer.file_name, name, 212); + message.data.data_xfer.file_name[211] = 0; + message.size = 44 + ((strlen(message.data.data_xfer.file_name) + 4) & + (~3u)); + + wimp_send_message_to_window(wimp_USER_MESSAGE, &message, + pointer.w, pointer.i); +} + + +/** + * Handle Message_DataSaveAck for a drag from the save dialog. + */ + +void ro_gui_save_datasave_ack(wimp_message *message) +{ + char *path = message->data.data_xfer.file_name; + os_error *error; + + if (!ro_gui_save(path)) return; + ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_PATH, reset_filename); + + /* Close the save window + */ + ro_gui_dialog_close(dialog_saveas); + + /* Ack successful save with message_DATA_LOAD */ + 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); + if (error) { + LOG(("xwimp_send_message_to_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + } + + if (close_menu) { + error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0); + if (error) { + LOG(("xwimp_create_menu: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MenuError", error->errmess); + } + } + close_menu = true; +} + +bool ro_gui_save(char *path) { + switch (gui_save_current_type) { + case SAVE_THEME: + return ro_gui_save_theme(path); + case SAVE_SPRITES: + return ro_gui_save_sprites(path); + } + return false; +} + +bool ro_gui_load_theme(char *path) { + os_error *error; + struct theme_file_header *file_header; + char *workspace; + int workspace_size, file_size, output_left; + fileswitch_object_type obj_type; + squash_output_status status; + os_fw file_handle; + char *raw_data; + char *compressed; + char *decompressed; + + /* Get memory for the header + */ + file_header = (struct theme_file_header *)calloc(1, + sizeof (struct theme_file_header)); + if (!file_header) { + LOG(("No memory for calloc()")); + warn_user("NoMemory", 0); + } + + /* Load the header + */ + error = xosfind_openinw(osfind_NO_PATH, path, 0, &file_handle); + if (error) { + free(file_header); + LOG(("xosfind_openinw: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + if (file_handle == 0) { + free(file_header); + LOG(("File not present")); + warn_user("FileError", error->errmess); + return false; + } + error = xosgbpb_read_atw(file_handle, (char *)file_header, + sizeof (struct theme_file_header), + 0, &output_left); + xosfind_closew(file_handle); + if (error) { + free(file_header); + LOG(("xosbgpb_read_atw: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + if (output_left > 0) { + free(file_header); + LOG(("Insufficient data")); + warn_user("FileError", error->errmess); + return false; + } + + /* Check the header is OK + */ + if ((file_header->magic_value != 0x4d54534e) || + (file_header->parser_version > 1)) return false; + + /* Try to load the sprite file + */ + if (file_header->decompressed_sprite_size > 0) { + error = xosfile_read_stamped_no_path(path, + &obj_type, 0, 0, &file_size, 0, 0); + if (error) { + free(file_header); + LOG(("xosfile_read_stamped_no_path: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + if (obj_type != fileswitch_IS_FILE) { + free(file_header); + return false; + } + raw_data = malloc(file_size); + if (!raw_data) { + free(file_header); + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + return false; + } + error = xosfile_load_stamped_no_path(path, (byte *)raw_data, + 0, 0, 0, 0, 0); + if (error) { + free(raw_data); + free(file_header); + LOG(("xosfile_load_stamped_no_path: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + + /* Decompress the data + */ + decompressed = malloc(file_header->decompressed_sprite_size); + if (!decompressed) { + free(raw_data); + free(file_header); + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + } + error = xsquash_decompress_return_sizes(-1, &workspace_size, 0); + if (error) { + free(decompressed); + free(raw_data); + free(file_header); + LOG(("xsquash_decompress_return_sizes: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + return false; + } + workspace = malloc(workspace_size); + if (!workspace) { + free(decompressed); + free(raw_data); + free(file_header); + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + return false; + } + compressed = raw_data + sizeof(struct theme_file_header); + error = xsquash_decompress(0, /*squash_INPUT_ALL_PRESENT,*/ + workspace, + (byte *)compressed, file_header->compressed_sprite_size, + (byte *)decompressed, file_header->decompressed_sprite_size, + &status, 0, 0, 0, 0); + free(workspace); + free(raw_data); + if (error) { + free(decompressed); + LOG(("xsquash_decompress: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + return false; + } + if (status != 0) { + free(decompressed); + return false; + } + if (theme_sprites) free(theme_sprites); + theme_sprites = (osspriteop_area *)decompressed; + } else { + if (theme_sprites) free(theme_sprites); + theme_sprites = NULL; + } + + /* Set out values + */ + ro_gui_set_icon_string(dialog_main, ICON_MAIN_NAME, file_header->name); + ro_gui_set_icon_string(dialog_main, ICON_MAIN_AUTHOR, file_header->author); + ro_gui_set_icon_background_colour(dialog_main, ICON_MAIN_BROWSER_COLOUR, + file_header->browser_bg); + ro_gui_set_icon_background_colour(dialog_main, ICON_MAIN_HOTLIST_COLOUR, + file_header->hotlist_bg); + ro_gui_set_icon_background_colour(dialog_main, ICON_MAIN_STATUSBG_COLOUR, + file_header->status_bg); + ro_gui_set_icon_background_colour(dialog_main, ICON_MAIN_STATUSFG_COLOUR, + file_header->status_fg); + ro_gui_set_icon_selected_state(dialog_main, ICON_MAIN_THROBBER_LEFT, + file_header->throbber_left); + + /* Remember the filename for saving later on + */ + if (theme_filename) free(theme_filename); + theme_filename = malloc(strlen(path) + 1); + sprintf(theme_filename, "%s", path); + if (sprite_filename) free(sprite_filename); + sprite_filename = NULL; + + /* Exit cleanly + */ + free(file_header); + return true; +} + +bool ro_gui_save_theme(char *path) { + os_error *error; + struct theme_file_header *file_header; + char *workspace; + int workspace_size, output_size, input_left, output_left; + squash_output_status status; + + /* Get some memory + */ + unsigned int file_size = sizeof (struct theme_file_header); + file_header = (struct theme_file_header *)calloc(file_size, 1); + if (!file_header) { + LOG(("No memory for calloc()")); + warn_user("NoMemory", 0); + return false; + } + + /* Complete the header + */ + file_header->magic_value = 0x4d54534e; + file_header->parser_version = 1; + strcpy(file_header->name, ro_gui_get_icon_string(dialog_main, ICON_MAIN_NAME)); + strcpy(file_header->author, ro_gui_get_icon_string(dialog_main, ICON_MAIN_AUTHOR)); + file_header->browser_bg = ro_gui_get_icon_background_colour(dialog_main, + ICON_MAIN_BROWSER_COLOUR); + file_header->hotlist_bg = ro_gui_get_icon_background_colour(dialog_main, + ICON_MAIN_HOTLIST_COLOUR); + file_header->status_bg = ro_gui_get_icon_background_colour(dialog_main, + ICON_MAIN_STATUSBG_COLOUR); + file_header->status_fg = ro_gui_get_icon_background_colour(dialog_main, + ICON_MAIN_STATUSFG_COLOUR); + if (ro_gui_get_icon_selected_state(dialog_main, ICON_MAIN_THROBBER_LEFT)) { + file_header->throbber_left = 0xff; + } + + /* Append the compressed sprites + */ + if (theme_sprites) { + file_header->decompressed_sprite_size = theme_sprites->size; + error = xsquash_compress_return_sizes(theme_sprites->size, + &workspace_size, &output_size); + if (error) { + free(file_header); + LOG(("xsquash_compress_return_sizes: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + return false; + } + workspace = realloc(file_header, + file_size + output_size); + if (!workspace) { + free(file_header); + LOG(("No memory for realloc()")); + warn_user("NoMemory", 0); + return false; + } + file_header = (struct theme_file_header *)workspace; + workspace = malloc(workspace_size); + if (!workspace) { + free(file_header); + LOG(("No memory for malloc()")); + warn_user("NoMemory", 0); + return false; + } + error = xsquash_compress((squash_input_status)0, + workspace, (byte *)theme_sprites, + theme_sprites->size, + (byte *)(file_header + 1), output_size, + &status, + 0, &input_left, 0, &output_left); + free(workspace); + if (error) { + free(file_header); + LOG(("xsquash_compress: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + return false; + } + if ((input_left > 0) || (status != 0)) { + free(file_header); + LOG(("Failed to complete compression with %i bytes left and status %i", + input_left, (int)status)); + warn_user("FileError", 0); + return false; + } + file_header->compressed_sprite_size = output_size - output_left; + file_size += output_size - output_left; + } + + /* Save the file + */ + error = xosfile_save_stamped(path, (bits)0xffd, + (char *)file_header, ((char *)file_header) + file_size); + free(file_header); + if (error) { + LOG(("xosfile_save_stamped: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + return false; +} + +bool ro_gui_save_sprites(char *path) { + os_error *error; + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + theme_sprites, path); + if (error) { + LOG(("xosfile_save_sprite_file: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return false; + } + if (sprite_filename) { + free(sprite_filename); + sprite_filename = NULL; + } + sprite_filename = malloc(strlen(path) + 1); + if (!sprite_filename) return true; + sprintf(sprite_filename, "%s", path); + return true; +} diff --git a/riscos/wimp.c b/riscos/wimp.c new file mode 100644 index 0000000..bb97ec6 --- /dev/null +++ b/riscos/wimp.c @@ -0,0 +1,556 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * General RISC OS WIMP/OS library functions (implementation). + */ + +#include +#include +#include +#include +#include +#include "oslib/os.h" +#include "oslib/osfile.h" +#include "oslib/wimp.h" +#include "oslib/wimpextend.h" +#include "oslib/wimpreadsysinfo.h" +#include "oslib/wimpspriteop.h" +#include "nstheme/desktop/gui.h" +#include "nstheme/riscos/gui.h" +#include "nstheme/riscos/wimp.h" +#include "nstheme/utils/log.h" +#include "nstheme/utils/utils.h" + +/* Wimp_Extend,11 block +*/ +static wimpextend_furniture_sizes furniture_sizes; + + +/** + * Gets the horzontal scrollbar height + */ +int ro_get_hscroll_height(wimp_w w) { + wimp_version_no version; + + /* Read the hscroll height + */ + if (!w) return 38; + furniture_sizes.w = w; + furniture_sizes.border_widths.y0 = 38; + xwimpextend_get_furniture_sizes(&furniture_sizes); + + /* There is a quirk with the returned size as it differs between versions of the + WindowManager module. The incorrect height is returned by the version distributed + with the universal boot sequence (3.98) and presumably any previous version. + */ + if (!xwimpreadsysinfo_version(&version)) { + if ((int)version <= 398) { + return furniture_sizes.border_widths.y0 + 2; + } + } + + /* Return the standard (unhacked) size + */ + return furniture_sizes.border_widths.y0; +} + + +/** + * Gets the vertical scrollbar width + */ +int ro_get_vscroll_width(wimp_w w) { + + /* Read the hscroll height + */ + if (!w) return 38; + furniture_sizes.w = w; + furniture_sizes.border_widths.x1 = 38; + xwimpextend_get_furniture_sizes(&furniture_sizes); + + /* Return the standard (unhacked) size + */ + return furniture_sizes.border_widths.x1; +} + + +/** + * Reads a modes EIG factors. + * + * \param mode mode to read EIG factors for, or -1 for current + */ +struct eig_factors ro_read_eig_factors(os_mode mode) { + bits psr; + struct eig_factors factors; + xos_read_mode_variable(mode, os_MODEVAR_XEIG_FACTOR, &factors.xeig, &psr); + xos_read_mode_variable(mode, os_MODEVAR_YEIG_FACTOR, &factors.yeig, &psr); + return factors; +} + + +/** + * Converts the supplied os_coord from OS units to pixels. + * + * \param os_units values to convert + * \param mode mode to use EIG factors for, or -1 for current + */ +void ro_convert_os_units_to_pixels(os_coord *os_units, os_mode mode) { + struct eig_factors factors = ro_read_eig_factors(mode); + os_units->x = (os_units->x >> factors.xeig); + os_units->y = (os_units->y >> factors.yeig); +} + + +/** + * Converts the supplied os_coord from pixels to OS units. + * + * \param pixels values to convert + * \param mode mode to use EIG factors for, or -1 for current + */ +void ro_convert_pixels_to_os_units(os_coord *pixels, os_mode mode) { + struct eig_factors factors = ro_read_eig_factors(mode); + pixels->x = (pixels->x << factors.xeig); + pixels->y = (pixels->y << factors.yeig); +} + + +/** + * Redraws an icon + * + * \param w window handle + * \param i icon handle + */ +#define ro_gui_redraw_icon(w, i) xwimp_set_icon_state(w, i, 0, 0) + + +/** + * Read the contents of an icon. + * + * \param w window handle + * \param i icon handle + * \return string in icon + */ +char *ro_gui_get_icon_string(wimp_w w, wimp_i i) { + char *text; + int size; + wimp_icon_state ic; + ic.w = w; + ic.i = i; + if (xwimp_get_icon_state(&ic)) return NULL; + text = ic.icon.data.indirected_text.text; + size = ic.icon.data.indirected_text.size; + text[size - 1] = '\0'; + while (text[0]) { + if (text[0] < 32) { + text[0] = '\0'; + } else { + text++; + } + } + return ic.icon.data.indirected_text.text; +} + + +/** + * Set the contents of an icon to a string. + * + * \param w window handle + * \param i icon handle + * \param text string (copied) + */ +void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text) { + wimp_caret caret; + wimp_icon_state ic; + int old_len, len; + + /* Get the icon data + */ + ic.w = w; + ic.i = i; + if (xwimp_get_icon_state(&ic)) + return; + + /* Check that the existing text is not the same as the updated text + to stop flicker + */ + if (ic.icon.data.indirected_text.size + && !strncmp(ic.icon.data.indirected_text.text, text, + (unsigned int)ic.icon.data.indirected_text.size - 1)) + return; + + /* Copy the text across + */ + old_len = strlen(ic.icon.data.indirected_text.text); + if (ic.icon.data.indirected_text.size) { + strncpy(ic.icon.data.indirected_text.text, text, + (unsigned int)ic.icon.data.indirected_text.size - 1); + ic.icon.data.indirected_text.text[ic.icon.data.indirected_text.size - 1] = '\0'; + } + + /* Handle the caret being in the icon + */ + if (!xwimp_get_caret_position(&caret)) { + if ((caret.w == w) && (caret.i == i)) { + len = strlen(text); + if ((caret.index > len) || (caret.index == old_len)) caret.index = len; + xwimp_set_caret_position(w, i, caret.pos.x, caret.pos.y, -1, caret.index); + } + } + + /* Redraw the icon + */ + ro_gui_redraw_icon(w, i); +} + + +/** + * Set the contents of an icon to a number. + * + * \param w window handle + * \param i icon handle + * \param value value + */ +void ro_gui_set_icon_integer(wimp_w w, wimp_i i, int value) { + char buffer[20]; // Big enough for 64-bit int + sprintf(buffer, "%d", value); + ro_gui_set_icon_string(w, i, buffer); +} + + +/** + * Set the selected state of an icon. + * + * \param w window handle + * \param i icon handle + * \param state selected state + */ +void ro_gui_set_icon_selected_state(wimp_w w, wimp_i i, bool state) { + os_error *error; + if (ro_gui_get_icon_selected_state(w, i) == state) return; + error = xwimp_set_icon_state(w, i, + (state ? wimp_ICON_SELECTED : 0), wimp_ICON_SELECTED); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } +} + +/** + * Gets the selected state of an icon. + * + * \param w window handle + * \param i icon handle + */ +bool ro_gui_get_icon_selected_state(wimp_w w, wimp_i i) { + os_error *error; + wimp_icon_state ic; + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return false; + } + return ((ic.icon.flags & wimp_ICON_SELECTED) != 0); +} + + +/** + * Set the shaded state of an icon. + * + * \param w window handle + * \param i icon handle + * \param state selected state + */ +void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state) { + os_error *error; + if (ro_gui_get_icon_shaded_state(w, i) == state) return; + error = xwimp_set_icon_state(w, i, + (state ? wimp_ICON_SHADED : 0), wimp_ICON_SHADED); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } +} + + +/** + * Gets the shaded state of an icon. + * + * \param w window handle + * \param i icon handle + */ +bool ro_gui_get_icon_shaded_state(wimp_w w, wimp_i i) { + wimp_icon_state ic; + ic.w = w; + ic.i = i; + xwimp_get_icon_state(&ic); + return (ic.icon.flags & wimp_ICON_SHADED) != 0; +} + + +/** + * Set the background colour of an icon. + * + * \param w window handle + * \param i icon handle + * \param state selected state + */ +void ro_gui_set_icon_background_colour(wimp_w w, wimp_i i, int colour) { + os_error *error; + if (ro_gui_get_icon_background_colour(w, i) == colour) return; + error = xwimp_set_icon_state(w, i, + (colour <errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } +} + + +/** + * Gets the background colour of an icon. + * + * \param w window handle + * \param i icon handle + */ +int ro_gui_get_icon_background_colour(wimp_w w, wimp_i i) { + os_error *error; + wimp_icon_state ic; + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return -1; + } + return ((ic.icon.flags >> wimp_ICON_BG_COLOUR_SHIFT) & 15); +} + + +/** + * Set a window title (does *not* redraw the title) + * + * \param w window handle + * \param text new title (copied) + */ +void ro_gui_set_window_title(wimp_w w, const char *text) { + wimp_window_info_base window; + os_error *error; + + /* Get the window details + */ + window.w = w; + error = xwimp_get_window_info_header_only((wimp_window_info *)&window); + if (error) { + LOG(("xwimp_get_window_info: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + /* Set the title string + */ + strncpy(window.title_data.indirected_text.text, text, + (unsigned int)window.title_data.indirected_text.size - 1); + window.title_data.indirected_text.text[window.title_data.indirected_text.size - 1] = '\0'; +} + + +/** + * Places the caret in the first available icon + */ +void ro_gui_set_caret_first(wimp_w w) { + int icon, button; + wimp_window_state win_state; + wimp_window_info_base window; + wimp_icon_state state; + wimp_caret caret; + os_error *error; + + /* Check the window is open + */ + win_state.w = w; + error = xwimp_get_window_state(&win_state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + if (!(win_state.flags & wimp_WINDOW_OPEN)) return; + + /* Check if the window already has the caret + */ + if (!xwimp_get_caret_position(&caret)) { + if (caret.w == w) return; + } + + /* Get the window details + */ + window.w = w; + error = xwimp_get_window_info_header_only((wimp_window_info *)&window); + if (error) { + LOG(("xwimp_get_window_info: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + /* Work through our icons + */ + state.w = w; + for (icon = 0; icon < window.icon_count; icon++) { + /* Get the icon state + */ + state.i = icon; + error = xwimp_get_icon_state(&state); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + /* Ignore if it's shaded + */ + if (state.icon.flags & wimp_ICON_SHADED) + continue; + + /* Check if it's writable + */ + button = (state.icon.flags >> wimp_ICON_BUTTON_TYPE_SHIFT) & 0xf; + if ((button == wimp_BUTTON_WRITE_CLICK_DRAG) || + (button == wimp_BUTTON_WRITABLE)) { + error = xwimp_set_caret_position(w, icon, 0, 0, -1, + strlen(state.icon.data.indirected_text.text)); + if (error) { + LOG(("xwimp_set_caret_position: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + return; + } + } +} + + +/** + * 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_open_window_centre(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) { + warn_user("WimpError", error->errmess); + return; + } + scroll_width = ro_get_vscroll_width(parent); + + /* Get the centre of the parent + */ + mid_x = (state.visible.x0 + state.visible.x1 + scroll_width) / 2; + mid_y = (state.visible.y0 + state.visible.y1) / 2; + } 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) { + warn_user("WimpError", error->errmess); + return; + } + if (!(state.flags & wimp_WINDOW_OPEN)) { + /* 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(child); + 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; + wimp_open_window((wimp_open *) &state); +} + + + +/** + * Load a sprite file into memory. + * + * \param pathname file to load + * \return sprite area, or 0 on memory exhaustion or error and error reported + */ + +osspriteop_area *ro_gui_load_sprite_file(const char *pathname) +{ + int len; + fileswitch_object_type obj_type; + osspriteop_area *area; + os_error *error; + + error = xosfile_read_stamped_no_path(pathname, + &obj_type, 0, 0, &len, 0, 0); + if (error) { + LOG(("xosfile_read_stamped_no_path: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + return 0; + } + if (obj_type != fileswitch_IS_FILE) { + warn_user("FileError", pathname); + return 0; + } + + area = malloc(len + 4); + if (!area) { + warn_user("NoMemory", 0); + return 0; + } + + area->size = len + 4; + area->sprite_count = 0; + area->first = 16; + area->used = 16; + + error = xosspriteop_load_sprite_file(osspriteop_USER_AREA, + area, pathname); + if (error) { + LOG(("xosspriteop_load_sprite_file: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + free(area); + return 0; + } + + return area; +} diff --git a/riscos/wimp.h b/riscos/wimp.h new file mode 100644 index 0000000..33c3ae7 --- /dev/null +++ b/riscos/wimp.h @@ -0,0 +1,51 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 Richard Wilson + */ + +/** \file + * General RISC OS WIMP/OS library functions (interface). + */ + + +#ifndef _NETSURF_RISCOS_WIMP_H_ +#define _NETSURF_RISCOS_WIMP_H_ + +#include +#include +#include +#include +#include +#include "oslib/os.h" +#include "oslib/wimp.h" + +struct eig_factors { + int xeig; + int yeig; +}; + + +int ro_get_hscroll_height(wimp_w w); +int ro_get_vscroll_width(wimp_w w); +struct eig_factors ro_read_eig_factors(os_mode mode); +void ro_convert_os_units_to_pixels(os_coord *os_units, os_mode mode); +void ro_convert_pixels_to_os_units(os_coord *pixels, os_mode mode); + +#define ro_gui_redraw_icon(w, i) xwimp_set_icon_state(w, i, 0, 0) +char *ro_gui_get_icon_string(wimp_w w, wimp_i i); +void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text); +void ro_gui_set_icon_integer(wimp_w w, wimp_i i, int value); +void ro_gui_set_icon_selected_state(wimp_w w, wimp_i i, bool state); +bool ro_gui_get_icon_selected_state(wimp_w w, wimp_i i); +void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state); +bool ro_gui_get_icon_shaded_state(wimp_w w, wimp_i i); +int ro_gui_get_icon_background_colour(wimp_w w, wimp_i i); +void ro_gui_set_icon_background_colour(wimp_w w, wimp_i i, int colour); +void ro_gui_set_window_title(wimp_w w, const char *title); +void ro_gui_set_caret_first(wimp_w w); +void ro_gui_open_window_centre(wimp_w parent, wimp_w child); + +osspriteop_area *ro_gui_load_sprite_file(const char *pathname); +#endif diff --git a/utils/log.h b/utils/log.h new file mode 100644 index 0000000..65417b9 --- /dev/null +++ b/utils/log.h @@ -0,0 +1,26 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 James Bursa + * Copyright 2004 John Tytgat + */ + +#include + +#ifndef _NETSURF_LOG_H_ +#define _NETSURF_LOG_H_ + +#ifdef NDEBUG +# define LOG(x) ((void) 0) +#else +# ifdef __GNUC__ +# define LOG(x) (printf(__FILE__ " %s %i: ", __PRETTY_FUNCTION__, __LINE__), printf x, fputc('\n', stdout)) +# elif defined(__CC_NORCROFT) +# define LOG(x) (printf(__FILE__ " %s %i: ", __func__, __LINE__), printf x, fputc('\n', stdout)) +# else +# define LOG(x) (printf(__FILE__ " %i: ", __LINE__), printf x, fputc('\n', stdout)) +# endif +#endif + +#endif diff --git a/utils/messages.c b/utils/messages.c new file mode 100644 index 0000000..7cc10bb --- /dev/null +++ b/utils/messages.c @@ -0,0 +1,169 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 James Bursa + */ + +/** \file + * Localised message support (implementation). + * + * Native language messages are loaded from a file and stored hashed by key for + * fast access. + */ + +#include +#include +#include +#include +#include "nstheme/utils/log.h" +#include "nstheme/utils/messages.h" +#include "nstheme/utils/utils.h" + +/** We store the messages in a fixed-size hash table. */ +#define HASH_SIZE 77 + +/** Maximum length of a key. */ +#define MAX_KEY_LENGTH 24 + +/** Entry in the messages hash table. */ +struct messages_entry { + struct messages_entry *next; /**< Next entry in this hash chain. */ + char key[MAX_KEY_LENGTH]; + char value[1]; +}; + +/** Localised messages hash table. */ +static struct messages_entry *messages_table[HASH_SIZE]; + + +static unsigned int messages_hash(const char *s); + + +/** + * Read keys and values from messages file. + * + * \param path pathname of messages file + * + * The messages are merged with any previously loaded messages. Any keys which + * are present already are replaced with the new value. + * + * Exits through die() in case of error. + */ + +void messages_load(const char *path) +{ + char s[300]; + FILE *fp; + + fp = fopen(path, "r"); + if (!fp) { + snprintf(s, sizeof s, "Unable to open messages file " + "\"%.100s\": %s", path, strerror(errno)); + s[sizeof s - 1] = 0; + LOG(("%s", s)); + die(s); + } + + while (fgets(s, sizeof s, fp)) { + char *colon, *value; + unsigned int slot; + struct messages_entry *entry; + size_t length; + + if (s[0] == 0 || s[0] == '#') + continue; + + s[strlen(s) - 1] = 0; /* remove \n at end */ + colon = strchr(s, ':'); + if (!colon) + continue; + *colon = 0; /* terminate key */ + value = colon + 1; + length = strlen(value); + + entry = malloc(sizeof *entry + length + 1); + if (!entry) { + snprintf(s, sizeof s, "Not enough memory to load " + "messages file \"%.100s\".", path); + s[sizeof s - 1] = 0; + LOG(("%s", s)); + die(s); + } + strncpy(entry->key, s, MAX_KEY_LENGTH); + strcpy(entry->value, value); + slot = messages_hash(entry->key); + entry->next = messages_table[slot]; + messages_table[slot] = entry; + } + + fclose(fp); +} + + +/** + * Fast lookup of a message by key. + * + * \param key key of message + * \return value of message, or key if not found + */ + +const char *messages_get(const char *key) +{ + struct messages_entry *entry; + + for (entry = messages_table[messages_hash(key)]; + entry && strcasecmp(entry->key, key) != 0; + entry = entry->next) + ; + if (!entry) + return key; + return entry->value; +} + +/** + * Retrieve the key associated with a value + * + * \param value The value as returned by messages_get + * \return The key associated with the value or NULL if not found + */ +const char *messages_get_key(const char *value) +{ + const char *key = value - MAX_KEY_LENGTH; + const char *temp_value = messages_get(key); + + if (strcmp(value, temp_value) == 0) + return key; + + return NULL; +} + + +/** + * Hash function for keys. + */ + +unsigned int messages_hash(const char *s) +{ + unsigned int i, z = 0; + if (!s) + return 0; + for (i = 0; i != MAX_KEY_LENGTH && s[i]; i++) + z += s[i] & 0x1f; /* lower 5 bits, case insensitive */ + return z % HASH_SIZE; +} + + +/** + * Dump set of loaded messages. + */ + +void messages_dump(void) +{ + unsigned int i; + for (i = 0; i != HASH_SIZE; i++) { + struct messages_entry *entry; + for (entry = messages_table[i]; entry; entry = entry->next) + printf("%.20s:%s\n", entry->key, entry->value); + } +} diff --git a/utils/messages.h b/utils/messages.h new file mode 100644 index 0000000..33b2fc3 --- /dev/null +++ b/utils/messages.h @@ -0,0 +1,29 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 James Bursa + */ + +/** \file + * Localised message support (interface). + * + * The messages module loads a file of keys and associated strings, and + * provides fast lookup by key. The messages file consists of key:value lines, + * comment lines starting with #, and other lines are ignored. Use + * messages_load() to read the file into memory. To lookup a key, use + * messages_get("key"). + * + * Only the first MAX_KEY_LENGTH (currently 24) characters of the key are + * significant. + */ + +#ifndef _NETSURF_UTILS_MESSAGES_H_ +#define _NETSURF_UTILS_MESSAGES_H_ + +void messages_load(const char *path); +const char *messages_get(const char *key); +const char *messages_get_key(const char *value); +void messages_dump(void); + +#endif diff --git a/utils/utils.c b/utils/utils.c new file mode 100644 index 0000000..4e7d80f --- /dev/null +++ b/utils/utils.c @@ -0,0 +1,30 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 James Bursa + * Copyright 2003 Phil Mellor + * Copyright 2003 John M Bell + * Copyright 2004 John Tytgat + */ + +#include +#include +#include +#include +#include +#include "nstheme/utils/utils.h" + +/** + * Check if a directory exists. + */ + +bool is_dir(const char *path) +{ + struct stat s; + + if (stat(path, &s)) + return false; + + return S_ISDIR(s.st_mode) ? true : false; +} diff --git a/utils/utils.h b/utils/utils.h new file mode 100644 index 0000000..7f52acf --- /dev/null +++ b/utils/utils.h @@ -0,0 +1,23 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 James Bursa + * Copyright 2004 John Tytgat + */ + +#ifndef _NETSURF_UTILS_UTILS_H_ +#define _NETSURF_UTILS_UTILS_H_ + +#include +#include +#include +#include +#include +#include "libxml/encoding.h" + +void die(const char * const error); +bool is_dir(const char *path); +void warn_user(const char *warning, const char *detail); + +#endif -- cgit v1.2.3