diff options
Diffstat (limited to 'riscos/wimp_event.c')
-rw-r--r-- | riscos/wimp_event.c | 1814 |
1 files changed, 0 insertions, 1814 deletions
diff --git a/riscos/wimp_event.c b/riscos/wimp_event.c deleted file mode 100644 index 015e87baf..000000000 --- a/riscos/wimp_event.c +++ /dev/null @@ -1,1814 +0,0 @@ -/* - * Copyright 2005 Richard Wilson <info@tinct.net> - * Copyright 2010, 2011 Stephen Fryatt <stevef@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** \file - * Automated RISC OS WIMP event handling (implementation). - */ - -#include <assert.h> -#include <inttypes.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include "oslib/os.h" -#include "oslib/osbyte.h" -#include "oslib/serviceinternational.h" -#include "oslib/wimp.h" - -#include "utils/log.h" - -#include "riscos/gui.h" -#include "riscos/dialog.h" -#include "riscos/menus.h" -#include "riscos/ucstables.h" -#include "riscos/wimp.h" -#include "riscos/wimp_event.h" -#include "riscos/wimputils.h" - -#define WIN_HASH_SIZE 32 -#define WIN_HASH(w) (((unsigned)(w) >> 5) % WIN_HASH_SIZE) - -typedef enum { - EVENT_NUMERIC_FIELD, - EVENT_TEXT_FIELD, - EVENT_UP_ARROW, - EVENT_DOWN_ARROW, - EVENT_MENU_GRIGHT, - EVENT_CHECKBOX, - EVENT_RADIO, - EVENT_BUTTON, - EVENT_CANCEL, - EVENT_OK -} event_type; - -struct event_data_numeric_field { - int stepping; - int min; - int max; - int decimal_places; -}; - -struct event_data_menu_gright { - wimp_i field; - wimp_menu *menu; -}; - -struct icon_event { - event_type type; - wimp_i i; - union { - struct event_data_numeric_field numeric_field; - struct event_data_menu_gright menu_gright; - wimp_i linked_icon; - int radio_group; - void (*callback)(wimp_pointer *pointer); - } data; - union { - char *textual; - bool boolean; - } previous_value; - bool previous_shaded; - struct icon_event *next; -}; - -struct event_window { - wimp_w w; - bool (*ok_click)(wimp_w w); - bool (*mouse_click)(wimp_pointer *pointer); - bool (*keypress)(wimp_key *key); - void (*open_window)(wimp_open *open); - void (*close_window)(wimp_w w); - void (*redraw_window)(wimp_draw *redraw); - void (*scroll_window)(wimp_scroll *scroll); - void (*entering_window)(wimp_entering *entering); - bool (*menu_prepare)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_pointer *p); - bool (*menu_selection)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_selection *s, menu_action a); - void (*menu_warning)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_selection *s, menu_action a); - void (*menu_close)(wimp_w w, wimp_i i, wimp_menu *m); - wimp_menu *window_menu; - bool window_menu_auto; - bool window_menu_iconbar; - const char *help_prefix; - const char *(*get_help_suffix)(wimp_w w, wimp_i i, os_coord *pos, - wimp_mouse_state buttons); - void *user_data; - struct icon_event *first; - struct event_window *next; - int max_radio_group; -}; - -static void ro_gui_wimp_event_ok_click(struct event_window *window, - wimp_mouse_state state); -static struct event_window *ro_gui_wimp_event_get_window(wimp_w w); -static struct event_window *ro_gui_wimp_event_find_window(wimp_w w); -static struct icon_event *ro_gui_wimp_event_get_event(wimp_w w, wimp_i i, - event_type type); -static void ro_gui_wimp_event_prepare_gright_menu(wimp_w w, struct icon_event *event); -static struct event_window *ro_gui_wimp_event_remove_window(wimp_w w); - -static struct event_window *ro_gui_wimp_event_windows[WIN_HASH_SIZE]; - -static wimp_w ro_gui_wimp_event_submenu; - -/** - * Memorises the current state of any registered components in a window. - * - * \param w the window to memorise - * \return true on success, false on memory exhaustion or for an unknown window - */ -bool ro_gui_wimp_event_memorise(wimp_w w) -{ - struct event_window *window; - struct icon_event *event; - bool error = false; - - window = ro_gui_wimp_event_find_window(w); - if (!window) - return false; - - for (event = window->first; event; event = event->next) { - switch (event->type) { - case EVENT_NUMERIC_FIELD: - case EVENT_TEXT_FIELD: - if (event->previous_value.textual) - free(event->previous_value.textual); - event->previous_value.textual = strdup( - ro_gui_get_icon_string(window->w, event->i)); - if (!event->previous_value.textual) { - error = true; - LOG("Unable to store state for icon %i", event->i); - } - break; - case EVENT_CHECKBOX: - case EVENT_RADIO: - event->previous_value.boolean = - ro_gui_get_icon_selected_state(window->w, event->i); - break; - default: - break; - } - if (event->type != EVENT_MENU_GRIGHT) - event->previous_shaded = ro_gui_get_icon_shaded_state(window->w, - event->i); - } - return !error; -} - - -/** - * Restore the state of any registered components in a window to their memorised state. - * - * \param w the window to restore - * \return true on success, false for an unknown window - */ -bool ro_gui_wimp_event_restore(wimp_w w) -{ - struct event_window *window; - struct icon_event *event; - - window = ro_gui_wimp_event_find_window(w); - if (!window) - return false; - - for (event = window->first; event; event = event->next) { - switch (event->type) { - case EVENT_NUMERIC_FIELD: - case EVENT_TEXT_FIELD: - if (event->previous_value.textual) - ro_gui_set_icon_string(window->w, event->i, - event->previous_value.textual, true); - break; - case EVENT_CHECKBOX: - case EVENT_RADIO: - ro_gui_set_icon_selected_state(window->w, event->i, - event->previous_value.boolean); - break; - default: - break; - } - if (event->type != EVENT_MENU_GRIGHT) - ro_gui_set_icon_shaded_state(window->w, event->i, - event->previous_shaded); - } - return true; -} - - -/** - * Ensures all values are within pre-determined boundaries. - * - * \param w the window to memorise - * \return true on success, false for an unknown window - */ -bool ro_gui_wimp_event_validate(wimp_w w) -{ - struct event_window *window; - struct icon_event *event; - int value; - - window = ro_gui_wimp_event_find_window(w); - if (!window) - return false; - - for (event = window->first; event; event = event->next) { - switch (event->type) { - case EVENT_NUMERIC_FIELD: - value = ro_gui_get_icon_decimal(window->w, event->i, - event->data.numeric_field.decimal_places); - if (value < event->data.numeric_field.min) - value = event->data.numeric_field.min; - else if (value > event->data.numeric_field.max) - value = event->data.numeric_field.max; - ro_gui_set_icon_decimal(window->w, event->i, value, - event->data.numeric_field.decimal_places); - break; - default: - break; - } - } - return true; -} - -/** - * Transfer event data from one window to another. This can be used as an - * alternative to ro_gui_wimp_event_finalise() and re-registering, if - * events need to continue across a change of window handle. - * - * All aspects of the registered events MUST remain the same in the new - * window! - * - * \param from The current window, which is to be deleted. - * \param to The window to which the events should transfer. - * \return true on success; false for an unknown window. - */ - -bool ro_gui_wimp_event_transfer(wimp_w from, wimp_w to) -{ - struct event_window *window; - int h; - - LOG("Transferring all events from window 0x%x to window 0x%x", (unsigned int)from, (unsigned int)to); - - window = ro_gui_wimp_event_remove_window(from); - if (window == NULL || window->w != from) - return false; - - h = WIN_HASH(to); - window->w = to; - window->next = ro_gui_wimp_event_windows[h]; - ro_gui_wimp_event_windows[h] = window; - - ro_gui_menu_window_changed(from, to); - - return true; -} - -/** - * Free any resources associated with a window. - * - * \param w the window to free resources for - */ -void ro_gui_wimp_event_finalise(wimp_w w) -{ - struct event_window *window; - struct icon_event *event; - - LOG("Removing all events for window 0x%x", (unsigned int)w); - window = ro_gui_wimp_event_remove_window(w); - if (!window) - return; - - while (window->first) { - event = window->first; - window->first = event->next; - switch (event->type) { - case EVENT_NUMERIC_FIELD: - case EVENT_TEXT_FIELD: - if (event->previous_value.textual) - free(event->previous_value.textual); - event->previous_value.textual = NULL; - break; - default: - break; - } - free(event); - } - free(window); - return; -} - - -/** - * Free any resources associated with a specific icon in a window. - * - * \param w The window containing the icon. - * \param i The icon to free resources for. - */ - -void ro_gui_wimp_event_deregister(wimp_w w, wimp_i i) -{ - struct event_window *window; - struct icon_event *event, *parent, *child; - - LOG("Removing all events for window 0x%x, icon %d", (unsigned int)w, (int)i); - window = ro_gui_wimp_event_get_window(w); - if (!window) - return; - - /* Remove any events that apply to the given icon. */ - - event = window->first; - parent = NULL; - - while (event != NULL) { - child = event->next; - - if (event->i == i) { - LOG("Removing event 0x%x", (unsigned int)event); - - if (parent == NULL) - window->first = child; - else - parent->next = child; - - switch (event->type) { - case EVENT_NUMERIC_FIELD: - case EVENT_TEXT_FIELD: - if (event->previous_value.textual) - free(event->previous_value.textual); - event->previous_value.textual = NULL; - break; - default: - break; - } - - free(event); - } else { - parent = event; - } - - event = child; - } -} - - -/** - * Set the associated help prefix for a given window. - * - * \param w the window to get the prefix for - * \param help_prefix the prefix to associate with the window (used directly) - * \return true on success, or NULL for memory exhaustion - */ -bool ro_gui_wimp_event_set_help_prefix(wimp_w w, const char *help_prefix) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->help_prefix = help_prefix; - return true; -} - - -/** - * Get the associated help prefix. - * - * \param w the window to get the prefix for - * \return the associated prefix, or NULL - */ -const char *ro_gui_wimp_event_get_help_prefix(wimp_w w) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(w); - if (window) - return window->help_prefix; - return NULL; -} - - -/** - * Register a handler to decode help suffixes for a given window. - * - */ - -bool ro_gui_wimp_event_register_help_suffix(wimp_w w, - const char *(*get_help_suffix)(wimp_w w, wimp_i i, - os_coord *pos, wimp_mouse_state buttons)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->get_help_suffix = get_help_suffix; - return true; -} - - -/** - * Get the associated help suffix. - * - * \param w The window to get the suffix for - * \param i The icon - * \param pos The os coordinates - * \param buttons The button state. - * \return The associated prefix, or NULL - */ - -const char *ro_gui_wimp_event_get_help_suffix(wimp_w w, wimp_i i, - os_coord *pos, wimp_mouse_state buttons) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(w); - if (window == NULL || window->get_help_suffix == NULL) - return NULL; - - return window->get_help_suffix(w, i, pos, buttons); -} - - -/** - * Sets the user data associated with a window. - * - * \param w the window to associate the data with - * \param user the data to associate - */ -bool ro_gui_wimp_event_set_user_data(wimp_w w, void *user) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->user_data = user; - return true; - -} - - -/** - * Gets the user data associated with a window. - * - * \param w the window to retrieve the data for - * \return the associated data, or NULL - */ -void *ro_gui_wimp_event_get_user_data(wimp_w w) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(w); - if (window) - return window->user_data; - return NULL; -} - - -/** - * Handles a menu selection event. - * - * (At present, this is tied to being called from menus.c and relies on that - * module decoding the menu into an action code. If menus.c loses its - * menu handling in the future, such decoding might need to move here.) - * - * The order of execution is: - * - * 1. Try to match the menu to a pop-up menu. If successful, handle it as - * this. - * 2. Try to match the menu to a window menu. If successful, pass control to - * the menu's registered _select handler. - * 3. Return event as unhandled. - * - * \param w the window to owning the menu - * \param i the icon owning the menu - * \param menu the menu that has been selected - * \param selection the selection information - * \param action the menu action info from menus.c - * \return true if the menu is OK for an Adjust re-open; - * else false. - */ -bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action) -{ - struct event_window *window; - struct icon_event *event; - wimp_menu_entry *menu_entry; - wimp_key key; - os_error *error; - wimp_caret caret; - wimp_icon_state ic; - unsigned int button_type; - bool prepared; - - window = ro_gui_wimp_event_find_window(w); - if (window == NULL) - return false; - - /* Start by looking for an icon event that matches. If there isn't one, - * then return details for an unconnected menu. It's up to the - * event recipient to sort out if this is a window menu or not, based - * on the menu handle passed back. - */ - - for (event = window->first; event; event = event->next) - if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i)) - break; - if (!event) { - if (window->menu_selection) - window->menu_selection(window->w, wimp_ICON_WINDOW, - menu, selection, action); - - /* Prepare the menu pending a possible Adjust click. */ - if (window->menu_prepare) - if (!window->menu_prepare(window->w, wimp_ICON_WINDOW, - menu, NULL)) - return false; - - return true; - } - - menu_entry = &menu->entries[selection->items[0]]; - for (i = 1; selection->items[i] != -1; i++) - menu_entry = &menu_entry->sub_menu-> - entries[selection->items[i]]; - - /* if the entry is already ticked then we do nothing */ - if (menu_entry->menu_flags & wimp_MENU_TICKED) - return true; - - ro_gui_set_icon_string(window->w, event->data.menu_gright.field, - menu_entry->data.indirected_text.text, false); - if (window->menu_selection) - window->menu_selection(window->w, event->i, menu, - selection, action); - prepared = true; - if (window->menu_prepare) - prepared = window->menu_prepare(window->w, event->i, - menu, NULL); - if (prepared) - ro_gui_wimp_event_prepare_gright_menu(window->w, event); - - /* set the caret for writable icons and send a CTRL+U keypress to - * stimulate activity if needed */ - ic.w = window->w; - ic.i = event->data.menu_gright.field; - error = xwimp_get_icon_state(&ic); - if (error) { - LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - button_type = (ic.icon.flags & wimp_ICON_BUTTON_TYPE) >> wimp_ICON_BUTTON_TYPE_SHIFT; - if ((button_type != wimp_BUTTON_WRITABLE) && - (button_type != wimp_BUTTON_WRITE_CLICK_DRAG)) - return prepared; - error = xwimp_get_caret_position(&caret); - if (error) { - LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - if ((caret.w != window->w) || (caret.i != event->data.menu_gright.field)) { - error = xwimp_set_caret_position(window->w, event->data.menu_gright.field, - -1, -1, -1, strlen(menu_entry->data.indirected_text.text)); - if (error) { - LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - } - } - if (window->keypress) { - key.w = window->w; - key.c = 21; // ctrl+u - window->keypress(&key); - } - return prepared; -} - - -/** - * Handles a mouse click event in a registered window. - * - * The order of execution is: - * - * 1. If a menu click, and the window has an automatic window menu, this is - * processed immediately. - * 2. Any registered mouse_click routine (see ro_gui_wimp_register_mouse_click()) - * 3. If the current icon is not registered with a type then it is assumed that no - * action is necessary, and the click is deemed to have been handled. - * 4. If the registered mouse_click routine returned false, or there was no registered - * routine then the automated action for the registered icon type is performed - * - * \param pointer the current pointer state - * \return true if the event was handled, false otherwise - */ -bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer) -{ - struct event_window *window; - struct icon_event *event; - wimp_w w; - struct icon_event *search; - int current, step, stepping, min, max, decimal_places; - wimp_window_state open; - wimp_caret caret; - bool prepared; - - w = pointer->w; - window = ro_gui_wimp_event_find_window(w); - if (!window) - return false; - - /* Menu clicks take priority if there is an auto menu defined. */ - if ((pointer->buttons == wimp_CLICK_MENU) && - (window->window_menu != NULL) && - (window->window_menu_auto)) { - ro_gui_wimp_event_process_window_menu_click(pointer); - return true; - } - - /* registered routines take next priority */ - if ((window->mouse_click) && (window->mouse_click(pointer))) - return true; - - for (event = window->first; event; event = event->next) - if (event->i == pointer->i) - break; - if (!event) - return true; - - switch (event->type) { - case EVENT_NUMERIC_FIELD: - case EVENT_TEXT_FIELD: - break; - case EVENT_UP_ARROW: - case EVENT_DOWN_ARROW: - for (search = window->first; search; search = search->next) - if (search->i == event->data.linked_icon) break; - if (!search) { - LOG("Incorrect reference."); - return false; - } - stepping = search->data.numeric_field.stepping; - min = search->data.numeric_field.min; - max = search->data.numeric_field.max; - decimal_places = search->data.numeric_field.decimal_places; - - if (pointer->buttons & wimp_CLICK_ADJUST) - step = -stepping; - else if (pointer->buttons & wimp_CLICK_SELECT) - step = stepping; - else - return true; - if (event->type == EVENT_DOWN_ARROW) - step = -step; - - current = ro_gui_get_icon_decimal(pointer->w, event->data.linked_icon, - decimal_places); - current += step; - if (current < min) - current = min; - if (current > max) - current = max; - ro_gui_set_icon_decimal(pointer->w, event->data.linked_icon, current, - decimal_places); - break; - case EVENT_MENU_GRIGHT: - /* if there's already a menu open then we assume that we are part of it. - * to follow the standard RISC OS behaviour we add a 'send to the back' - * button, then close the menu (which closes us) and then finally - * re-open ourselves. ugh! */ - if (current_menu != NULL) { - os_error *error; - open.w = pointer->w; - error = xwimp_get_window_state(&open); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - error = xwimp_get_caret_position(&caret); - if (error) { - LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - ro_gui_dialog_add_persistent(current_menu_window, - pointer->w); - ro_gui_menu_destroy(); - error = xwimp_open_window(PTR_WIMP_OPEN(&open)); - if (error) { - LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return false; - } - if (caret.w == pointer->w) { - error = xwimp_set_caret_position(caret.w, - caret.i, - caret.pos.x, caret.pos.y, - -1, caret.index); - if (error) { - LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - } - } - } - /* display the menu */ - - prepared = true; - if (window->menu_prepare != NULL) - prepared = window->menu_prepare(pointer->w, pointer->i, - event->data.menu_gright.menu, pointer); - if (prepared) { - ro_gui_wimp_event_prepare_gright_menu(pointer->w, event); - ro_gui_popup_menu(event->data.menu_gright.menu, pointer->w, pointer->i); - } - break; - case EVENT_CHECKBOX: - break; - case EVENT_RADIO: - for (search = window->first; search; search = search->next) - if ((search->type == EVENT_RADIO) && - (search->data.radio_group == - event->data.radio_group)) - ro_gui_set_icon_selected_state(pointer->w, - search->i, (search == event)); - break; - case EVENT_BUTTON: - if (event->data.callback) - event->data.callback(pointer); - break; - case EVENT_CANCEL: - if (pointer->buttons & wimp_CLICK_SELECT) { - ro_gui_dialog_close(pointer->w); - ro_gui_wimp_event_close_window(pointer->w); - ro_gui_menu_destroy(); - } else { - ro_gui_wimp_event_restore(pointer->w); - } - break; - case EVENT_OK: - ro_gui_wimp_event_ok_click(window, pointer->buttons); - break; - } - return true; -} - - -/** - * Prepare a menu ready for use - * - * /param w the window owning the menu - * /param event the icon event owning the menu - */ -void ro_gui_wimp_event_prepare_gright_menu(wimp_w w, struct icon_event *event) -{ - int i; - const char *text; - unsigned int button_type; - wimp_icon_state ic; - wimp_menu *menu; - os_error *error; - - /* if the linked icon is not writable then we set the ticked state - * of the menu item that matches the contents */ - ic.w = w; - ic.i = event->data.menu_gright.field; - error = xwimp_get_icon_state(&ic); - if (error) { - LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); - return; - } - button_type = (ic.icon.flags & wimp_ICON_BUTTON_TYPE) - >> wimp_ICON_BUTTON_TYPE_SHIFT; - if ((button_type == wimp_BUTTON_WRITABLE) || - (button_type == wimp_BUTTON_WRITE_CLICK_DRAG)) - return; - text = ro_gui_get_icon_string(w, event->data.menu_gright.field); - menu = event->data.menu_gright.menu; - i = 0; - do { - if (!strcmp(menu->entries[i].data.indirected_text.text, text)) - menu->entries[i].menu_flags |= wimp_MENU_TICKED; - else - menu->entries[i].menu_flags &= ~wimp_MENU_TICKED; - } while (!(menu->entries[i++].menu_flags & wimp_MENU_LAST)); -} - - -/** - * Perform the necessary actions following a click on the OK button. - * - * /param window the window to perform the action on - * /param state the mouse button state - */ -void ro_gui_wimp_event_ok_click(struct event_window *window, - wimp_mouse_state state) -{ - struct icon_event *search; - - for (search = window->first; search; search = search->next) - if (search->type == EVENT_OK) { - if (ro_gui_get_icon_shaded_state(window->w, search->i)) - return; - break; - } - ro_gui_wimp_event_validate(window->w); - - if (window->ok_click) - if (!window->ok_click(window->w)) - return; - - if (state & wimp_CLICK_SELECT) { - ro_gui_dialog_close(window->w); - ro_gui_wimp_event_close_window(window->w); - ro_gui_menu_destroy(); - } else { - ro_gui_wimp_event_memorise(window->w); - } -} - - -/** - * Handle any registered keypresses, and the standard RISC OS ones - * - * \param key the key state - * \return true if keypress handled, false otherwise - */ -bool ro_gui_wimp_event_keypress(wimp_key *key) -{ - static const int *ucstable = NULL; - static int alphabet = 0; - static uint32_t wc = 0; /* buffer for UTF8 alphabet */ - static int shift = 0; - struct event_window *window; - struct icon_event *event; - wimp_pointer pointer; - wimp_key k; - uint32_t c = (uint32_t) key->c; - int t_alphabet; - os_error *error; - - window = ro_gui_wimp_event_find_window(key->w); - if (!window) - return false; - - /* copy key state so we can corrupt it safely */ - memcpy(&k, key, sizeof(wimp_key)); - - /* In order to make sensible use of the 0x80->0xFF ranges specified - * in the RISC OS 8bit alphabets, we must do the following: - * - * + Read the currently selected alphabet - * + Acquire a pointer to the UCS conversion table for this alphabet: - * + Try using ServiceInternational 8 to get the table - * + If that fails, use our internal table (see ucstables.c) - * + If the alphabet is not UTF8 and the conversion table exists: - * + Lookup UCS code in the conversion table - * + If code is -1 (i.e. undefined): - * + Use codepoint 0xFFFD instead - * + If the alphabet is UTF8, we must buffer input, thus: - * + If the keycode is < 0x80: - * + Handle it directly - * + If the keycode is a UTF8 sequence start: - * + Initialise the buffer appropriately - * + Otherwise: - * + OR in relevant bits from keycode to buffer - * + If we've received an entire UTF8 character: - * + Handle UCS code - * + Otherwise: - * + Simply handle the keycode directly, as there's no easy way - * of performing the mapping from keycode -> UCS4 codepoint. - */ - error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &t_alphabet); - if (error) { - LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess); - /* prevent any corruption of ucstable */ - t_alphabet = alphabet; - } - - if (t_alphabet != alphabet) { - void *ostable; - osbool unclaimed; - /* Alphabet has changed, so read UCS table location */ - alphabet = t_alphabet; - - error = xserviceinternational_get_ucs_conversion_table( - alphabet, &unclaimed, &ostable); - if (error != NULL) { - LOG("failed reading UCS conversion table: 0x%x: %s", error->errnum, error->errmess); - /* Try using our own table instead */ - ucstable = ucstable_from_alphabet(alphabet); - } else if (unclaimed) { - /* Service wasn't claimed so use our own ucstable */ - ucstable = ucstable_from_alphabet(alphabet); - } else { - /* Use the table provided by the OS */ - ucstable = ostable; - } - } - - if (c < 256) { - if (alphabet != 111 /* UTF8 */ && ucstable != NULL) { - /* defined in this alphabet? */ - if (ucstable[c] == -1) - return true; - - /* read UCS4 value out of table */ - k.c = ucstable[c]; - } - else if (alphabet == 111 /* UTF8 */) { - if ((c & 0x80) == 0x00 || (c & 0xC0) == 0xC0) { - /* UTF8 start sequence */ - if ((c & 0xE0) == 0xC0) { - wc = ((c & 0x1F) << 6); - shift = 1; - return true; - } - else if ((c & 0xF0) == 0xE0) { - wc = ((c & 0x0F) << 12); - shift = 2; - return true; - } - else if ((c & 0xF8) == 0xF0) { - wc = ((c & 0x07) << 18); - shift = 3; - return true; - } - /* These next two have been removed - * from RFC3629, but there's no - * guarantee that RISC OS won't - * generate a UCS4 value outside the - * UTF16 plane, so we handle them - * anyway. */ - else if ((c & 0xFC) == 0xF8) { - wc = ((c & 0x03) << 24); - shift = 4; - } - else if ((c & 0xFE) == 0xFC) { - wc = ((c & 0x01) << 30); - shift = 5; - } - else if (c >= 0x80) { - /* If this ever happens, - * RISC OS' UTF8 keyboard - * drivers are broken */ - LOG("unexpected UTF8 start"" byte %x (ignoring)", c); - return true; - } - /* Anything else is ASCII, so just - * handle it directly. */ - } - else { - if ((c & 0xC0) != 0x80) { - /* If this ever happens, - * RISC OS' UTF8 keyboard - * drivers are broken */ - LOG("unexpected keycode: ""%x (ignoring)", c); - return true; - } - - /* Continuation of UTF8 character */ - wc |= ((c & 0x3F) << (6 * --shift)); - if (shift > 0) - /* partial character */ - return true; - else - /* got entire character, so - * fetch from buffer and - * handle it */ - k.c = wc; - } - } - } else { - k.c |= IS_WIMP_KEY; - } - - /* registered routines take priority */ - if (window->keypress) - if (window->keypress(&k)) - return true; - - switch (key->c) { - /* Escape performs the CANCEL action (simulated click) */ - case wimp_KEY_ESCAPE: - for (event = window->first; event; event = event->next) { - switch (event->type) { - case EVENT_CANCEL: - pointer.w = key->w; - pointer.i = event->i; - pointer.buttons = wimp_CLICK_SELECT; - ro_gui_wimp_event_mouse_click(&pointer); - return true; - default: - break; - } - } - return false; - /* CTRL+F2 closes a window with a close icon */ - case wimp_KEY_CONTROL + wimp_KEY_F2: - if (!ro_gui_wimp_check_window_furniture(key->w, - wimp_WINDOW_CLOSE_ICON)) - return false; - ro_gui_dialog_close(key->w); - ro_gui_wimp_event_close_window(key->w); - ro_gui_menu_destroy(); - return true; - /* Return performs the OK action */ - case wimp_KEY_RETURN: - if (!window->ok_click) - return false; - /* todo: check we aren't greyed out */ - ro_gui_wimp_event_ok_click(window, wimp_CLICK_SELECT); - return true; - } - return false; -} - - -/** - * Handle any open window requests - * - * \param open the window open request - */ -bool ro_gui_wimp_event_open_window(wimp_open *open) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(open->w); - if ((window) && (window->open_window)) { - window->open_window(open); - return true; - } - return false; -} - - -/** - * Service any close window handlers - * - * \param w the window being closed - */ -bool ro_gui_wimp_event_close_window(wimp_w w) -{ - struct event_window *window; - - LOG("Close event received for window 0x%x", (unsigned int)w); - if (w == ro_gui_wimp_event_submenu) - ro_gui_wimp_event_submenu = 0; - window = ro_gui_wimp_event_find_window(w); - if ((window) && (window->close_window)) { - window->close_window(w); - return true; - } - return false; -} - - -/** - * Handle any redraw window requests - * - * \param redraw the window redraw request - */ -bool ro_gui_wimp_event_redraw_window(wimp_draw *redraw) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(redraw->w); - if ((window) && (window->redraw_window)) { - window->redraw_window(redraw); - return true; - } - return false; -} - - -/** - * Handle any scroll window requests - * - * \param scroll the window scroll request - */ -bool ro_gui_wimp_event_scroll_window(wimp_scroll *scroll) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(scroll->w); - if ((window) && (window->scroll_window)) { - window->scroll_window(scroll); - return true; - } - return false; -} - - -/** - * Handle any pointer entering window requests - * - * \param entering the pointer entering window request - */ -bool ro_gui_wimp_event_pointer_entering_window(wimp_entering *entering) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(entering->w); - if ((window) && (window->entering_window)) { - window->entering_window(entering); - return true; - } - return false; -} - - -/** - * Process a Menu click in a window, by checking for a registered window - * menu and opening it if one is found. - * - * \param pointer The pointer block from the mouse click event. - * \return true if the click was actioned; else false. - */ - -bool ro_gui_wimp_event_process_window_menu_click(wimp_pointer *pointer) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(pointer->w); - if ((window) && (window->window_menu) - && (pointer->buttons == wimp_CLICK_MENU)) { - int xpos, ypos; - - if (window->menu_prepare) - if (!window->menu_prepare(window->w, wimp_ICON_WINDOW, - window->window_menu, pointer)) - return false; - - if (window->window_menu_iconbar) { - int entry = 0; - int line_height = window->window_menu->height + - window->window_menu->gap; - int gap_height = 24; /* The fixed dotted line height */ - - xpos = pointer->pos.x; - ypos = 96; - do { - ypos += line_height; - if ((window->window_menu-> - entries[entry].menu_flags & - wimp_MENU_SEPARATE) != 0) - ypos += gap_height; - } while ((window->window_menu-> - entries[entry++].menu_flags & - wimp_MENU_LAST) == 0); - } else { - xpos = pointer->pos.x; - ypos = pointer->pos.y; - } - - ro_gui_menu_create(window->window_menu, xpos, ypos, window->w); - return true; - } - return false; -} - - -/** - * Trigger a window's Prepare Menu event. - * - * \param w The window to use. - * \param i The icon to use. - * \param *menu The menu handle to use. - * \return true if the affected menu was prepared OK; else - * false. - */ - -bool ro_gui_wimp_event_prepare_menu(wimp_w w, wimp_i i, wimp_menu *menu) -{ - struct event_window *window; - - window = ro_gui_wimp_event_find_window(w); - if (window == NULL) - return false; - - if (window->menu_prepare) - return window->menu_prepare(w, i, menu, NULL); - - /* The menu is always OK if there's no event handler. */ - - return true; -} - -/** - * Register a window menu to be (semi-)automatically handled. - * - * \param w The window to attach the menu to. - * \param m The menu to be attached. - * \param menu_auto true if the menu should be opened autimatically on - * Menu clicks with no task intervention; false to pass - * clicks to the window's Mouse Event handler and leave - * that to pass the menu click back to us for handling - * and menu opening. - * \param position_ibar true if the menu should open in an iconbar - * position; false to open at the pointer. - * \return true if the menu was registed ok; else false. - */ - -bool ro_gui_wimp_event_register_menu(wimp_w w, wimp_menu *m, - bool menu_auto, bool position_ibar) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->window_menu = m; - window->window_menu_auto = menu_auto; - window->window_menu_iconbar = position_ibar; - return true; -} - -/** - * Register a numeric field to be automatically handled - */ -bool ro_gui_wimp_event_register_numeric_field(wimp_w w, wimp_i i, - wimp_i up, wimp_i down, - int min, int max, int stepping, int decimal_places) -{ - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_NUMERIC_FIELD); - if (!event) - return false; - event->data.numeric_field.min = min; - event->data.numeric_field.max = max; - event->data.numeric_field.stepping = stepping; - event->data.numeric_field.decimal_places = decimal_places; - - event = ro_gui_wimp_event_get_event(w, up, EVENT_UP_ARROW); - if (!event) - return false; - event->data.linked_icon = i; - - event = ro_gui_wimp_event_get_event(w, down, EVENT_DOWN_ARROW); - if (!event) - return false; - event->data.linked_icon = i; - - return true; -} - - -/** - * Register a text field to be automatically handled - */ -bool ro_gui_wimp_event_register_text_field(wimp_w w, wimp_i i) { - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_TEXT_FIELD); - if (!event) - return false; - return true; -} - - -/** - * Register an icon menu to be automatically handled - */ -bool ro_gui_wimp_event_register_menu_gright(wimp_w w, wimp_i i, - wimp_i gright, wimp_menu *menu) -{ - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, gright, EVENT_MENU_GRIGHT); - if (!event) - return false; - event->data.menu_gright.field = i; - event->data.menu_gright.menu = menu; - - return ro_gui_wimp_event_register_text_field(w, i); -} - - -/** - * Register a checkbox to be automatically handled - */ -bool ro_gui_wimp_event_register_checkbox(wimp_w w, wimp_i i) -{ - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_CHECKBOX); - if (!event) - return false; - return true; -} - - -/** - * Register a group of radio icons to be automatically handled - */ -bool ro_gui_wimp_event_register_radio(wimp_w w, wimp_i *i) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->max_radio_group++; - - while (*i != -1) { - struct icon_event *event = ro_gui_wimp_event_get_event(w, *i, - EVENT_RADIO); - if (!event) - return false; - event->data.radio_group = window->max_radio_group; - i++; - } - return true; -} - - -/** - * Register a function to be called when a particular button is pressed. - */ -bool ro_gui_wimp_event_register_button(wimp_w w, wimp_i i, - void (*callback)(wimp_pointer *pointer)) -{ - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_BUTTON); - if (!event) - return false; - event->data.callback = callback; - return true; -} - - -/** - * Register a function to be called for the Cancel action on a window. - */ -bool ro_gui_wimp_event_register_cancel(wimp_w w, wimp_i i) -{ - struct icon_event *event; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_CANCEL); - if (!event) - return false; - return true; -} - - -/** - * Register a function to be called for the OK action on a window. - */ -bool ro_gui_wimp_event_register_ok(wimp_w w, wimp_i i, - bool (*callback)(wimp_w w)) -{ - struct event_window *window; - struct icon_event *event; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->ok_click = callback; - - event = ro_gui_wimp_event_get_event(w, i, EVENT_OK); - if (!event) - return false; - return true; -} - - -/** - * Register a function to be called for all mouse-clicks to icons - * in a window that don't have registered actions. - */ -bool ro_gui_wimp_event_register_mouse_click(wimp_w w, - bool (*callback)(wimp_pointer *pointer)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->mouse_click = callback; - return true; -} - - -/** - * Register a function to be called for all keypresses within a - * particular window. - * - * Important: the character code passed to the callback in key->c - * is UTF-32 (i.e. in the range [0, &10ffff]). WIMP keys (e.g. F1) - * will have bit 31 set. - * - */ -bool ro_gui_wimp_event_register_keypress(wimp_w w, - bool (*callback)(wimp_key *key)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->keypress = callback; - return true; -} - - -/** - * Register a function to be called for all window opening requests. - */ -bool ro_gui_wimp_event_register_open_window(wimp_w w, - void (*callback)(wimp_open *open)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->open_window = callback; - return true; -} - -/** - * Register a function to be called after the window has been closed. - */ -bool ro_gui_wimp_event_register_close_window(wimp_w w, - void (*callback)(wimp_w w)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->close_window = callback; - return true; -} - -/** - * Register a function to be called for all window redraw operations. - */ -bool ro_gui_wimp_event_register_redraw_window(wimp_w w, - void (*callback)(wimp_draw *redraw)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->redraw_window = callback; - return true; -} - -/** - * Register a function to be called for all window scroll requests. - */ - -bool ro_gui_wimp_event_register_scroll_window(wimp_w w, - void (*callback)(wimp_scroll *scroll)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->scroll_window = callback; - return true; -} - -/** - * Register a function to be called for all pointer entering window requests. - */ - -bool ro_gui_wimp_event_register_pointer_entering_window(wimp_w w, - void (*callback)(wimp_entering *entering)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->entering_window = callback; - return true; -} - -/** - * Register a function to be called before a menu is (re-)opened. - * - * \param *w The window for which events should be returned. - * \param *callback A function to be called beofre the menu is - * (re-)opened. - * \return true if the menu was registed ok; else false. - */ -bool ro_gui_wimp_event_register_menu_prepare(wimp_w w, - bool (*callback)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_pointer *p)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->menu_prepare = callback; - return true; -} - - -/** - * Register a function to be called following a menu selection. - * - * \param *w The window for which events should be returned. - * \param *callback A function to be called when a selection is - * made. - * \return true if the menu was registed ok; else false. - */ -bool ro_gui_wimp_event_register_menu_selection(wimp_w w, - bool (*callback)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_selection *s, menu_action a)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->menu_selection = callback; - return true; -} - - -/** - * Register a function to be called when a sub-menu warning is received. - * - * \param *w The window for which events should be returned. - * \param *callback A function to be called whenever a submenu - * warning is received for the menu. - * \return true if the menu was registed ok; else false. - */ -bool ro_gui_wimp_event_register_menu_warning(wimp_w w, - void (*callback)(wimp_w w, wimp_i i, wimp_menu *m, - wimp_selection *s, menu_action a)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->menu_warning = callback; - return true; -} - - -/** - * Register a function to be called before a menu is finally closed. - * - * \param *w The window for which events should be returned. - * \param *callback A function to be called when the menu is closed. - * \return true if the menu was registed ok; else false. - */ -bool ro_gui_wimp_event_register_menu_close(wimp_w w, - void (*callback)(wimp_w w, wimp_i i, wimp_menu *m)) -{ - struct event_window *window; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return false; - window->menu_close = callback; - return true; -} - - -/** - * Finds the event data associated with a given window handle, or creates a - * new one. - * - * \param w the window to find data for - */ -struct event_window *ro_gui_wimp_event_get_window(wimp_w w) -{ - struct event_window *window; - int h; - - assert((int)w != 0); - window = ro_gui_wimp_event_find_window(w); - if (window) - return window; - - LOG("Creating structure for window 0x%x", (unsigned int)w); - window = calloc(1, sizeof(struct event_window)); - if (!window) - return NULL; - - h = WIN_HASH(w); - window->w = w; - window->next = ro_gui_wimp_event_windows[h]; - ro_gui_wimp_event_windows[h] = window; - return window; -} - - -/** - * Removes the event data associated with a given handle from the hash tables, - * but does not delete it. - * - * \param w the window to be removed - * \return pointer to the event data or NULL if not found - */ - -struct event_window *ro_gui_wimp_event_remove_window(wimp_w w) -{ - struct event_window **prev; - int h = WIN_HASH(w); - - /* search hash chain for the window */ - prev = &ro_gui_wimp_event_windows[h]; - while (*prev) { - struct event_window *window = *prev; - - if (window->w == w) { - /* remove from chain */ - *prev = window->next; - return window; - } - prev = &window->next; - } - - /* not found */ - return NULL; -} - -/** - * Find the event data associated with a given window handle - * - * \param w the window to find data for - */ -struct event_window *ro_gui_wimp_event_find_window(wimp_w w) -{ - struct event_window *window; - int h = WIN_HASH(w); - - /* search hash chain for window */ - for (window = ro_gui_wimp_event_windows[h]; window; window = window->next) { - if (window->w == w) - return window; - } - return NULL; -} - -struct icon_event *ro_gui_wimp_event_get_event(wimp_w w, wimp_i i, - event_type type) -{ - struct event_window *window; - struct icon_event *event; - - window = ro_gui_wimp_event_get_window(w); - if (!window) - return NULL; - - for (event = window->first; event; event = event->next) { - if (event->i == i) { - event->type = type; - return event; - } - } - - event = calloc(1, sizeof(struct icon_event)); - if (!event) - return NULL; - event->i = i; - event->type = type; - event->next = window->first; - window->first = event; - - return event; -} - -/* Handle sumbenu warnings. This is called from ro_gui_menu_warning(), and - * returns to that function to have the submenu opened correctly. - * - * \param w the window to owning the menu - * \param i the icon owning the menu - * \param menu the menu that has been selected - * \param selection the selection information - * \param action the menu action info from menus.c - * \return true if the event was handled, false otherwise - */ - -bool ro_gui_wimp_event_submenu_warning(wimp_w w, wimp_i i, wimp_menu *menu, - wimp_selection *selection, menu_action action) -{ - struct event_window *window; - struct icon_event *event; - - ro_gui_wimp_event_register_submenu(0); - - /* Process the event for any window menus. Find the window data, then - * try and match to an icon event. If we can, then there isn't anything - * to do. - */ - - window = ro_gui_wimp_event_find_window(w); - if (!window) - return false; - - for (event = window->first; event; event = event->next) - if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i)) - break; - if (event) { - if (window->menu_close != NULL && - event->type == EVENT_MENU_GRIGHT && - event->data.menu_gright.menu == menu) { - window->menu_close(w, i, menu); - return true; - } - - return false; - } - - /* If the warning is for a window menu, then pass the event on to it. */ - - if ((window->window_menu) && (window->window_menu == menu)) { - if (window->menu_warning) { - window->menu_warning(w, wimp_ICON_WINDOW, menu, - selection, action); - return true; - } - } - - return false; -} - -/** - * Handle menus being closed. This is called from the menus modules, in - * every scenario when one of our own menus is open. - * - * \param w the window to owning the menu - * \param i the icon owning the menu - * \param menu the menu that has been selected - */ - -void ro_gui_wimp_event_menus_closed(wimp_w w, wimp_i i, wimp_menu *menu) -{ - struct event_window *window; - struct icon_event *event; - - ro_gui_wimp_event_register_submenu(0); - - /* Process the event for any window menus. Find the window data, then - * try and match to an icon event. If we can, then GRight menus are - * sent the event; otherwise, we do nothing. - */ - - window = ro_gui_wimp_event_find_window(w); - if (!window) - return; - - for (event = window->first; event; event = event->next) - if ((event->type == EVENT_MENU_GRIGHT) && (event->i == i)) - break; - if (event) { - if (window->menu_close != NULL && - event->type == EVENT_MENU_GRIGHT && - event->data.menu_gright.menu == menu) - window->menu_close(w, i, menu); - return; - } - - /* If the close is for a window menu, then pass the event on to it. */ - - if ((window->window_menu) && (window->window_menu == menu) && - (window->menu_close)) - window->menu_close(w, wimp_ICON_WINDOW, menu); -} - -/** - * Register a submenu as being opened - */ -void ro_gui_wimp_event_register_submenu(wimp_w w) -{ - if (ro_gui_wimp_event_submenu) - ro_gui_wimp_event_close_window(ro_gui_wimp_event_submenu); - ro_gui_wimp_event_submenu = w; -} - |