diff options
author | Richard Wilson <rjw@netsurf-browser.org> | 2004-11-07 19:19:11 +0000 |
---|---|---|
committer | Richard Wilson <rjw@netsurf-browser.org> | 2004-11-07 19:19:11 +0000 |
commit | 5e41fb8a121c441a8765a1962a892e93906cde83 (patch) | |
tree | 0fd0a6aa6adbd7275b7a2fd9216d1e063a968ad0 /riscos/gui.c | |
download | nstheme-5e41fb8a121c441a8765a1962a892e93906cde83.tar.gz nstheme-5e41fb8a121c441a8765a1962a892e93906cde83.tar.bz2 |
[project @ 2004-11-07 19:19:11 by rjw]
Initial import.
svn path=/import/nstheme/; revision=2436
Diffstat (limited to 'riscos/gui.c')
-rw-r--r-- | riscos/gui.c | 608 |
1 files changed, 608 insertions, 0 deletions
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 <monkeyson@users.sourceforge.net> + * Copyright 2004 James Bursa <bursa@users.sourceforge.net> + * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk> + * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net> + */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unixlib/features.h> +#include <unixlib/local.h> +#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), + "<NSTheme$Dir>.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), + "<NSTheme$Dir>.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, "<NSTheme$Dir>.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, "<NSTheme$Dir>.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("<Choices$Write>.NSTheme", 0); + options_write("<Choices$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 <NSTheme$Dir>.!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); +} |