summaryrefslogtreecommitdiff
path: root/frontends/riscos/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/riscos/message.c')
-rw-r--r--frontends/riscos/message.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/frontends/riscos/message.c b/frontends/riscos/message.c
new file mode 100644
index 000000000..1c54ea0b7
--- /dev/null
+++ b/frontends/riscos/message.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Automated RISC OS message routing (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include "oslib/os.h"
+#include "oslib/wimp.h"
+
+#include "utils/log.h"
+
+#include "riscos/message.h"
+#include "riscos/gui.h"
+
+struct active_message {
+ unsigned int message_code;
+ int id;
+ void (*callback)(wimp_message *message);
+ struct active_message *next;
+ struct active_message *previous;
+};
+struct active_message *current_messages = NULL;
+
+static struct active_message *ro_message_add(unsigned int message_code,
+ void (*callback)(wimp_message *message));
+static void ro_message_free(int ref);
+
+
+/**
+ * Sends a message and registers a return route for a bounce.
+ *
+ * \param event the message event type
+ * \param message the message to register a route back for
+ * \param task the task to send a message to, or 0 for broadcast
+ * \param callback the code to call on a bounce
+ * \return true on success, false otherwise
+ */
+bool ro_message_send_message(wimp_event_no event, wimp_message *message,
+ wimp_t task, void (*callback)(wimp_message *message))
+{
+ os_error *error;
+
+ assert(message);
+
+ /* send a message */
+ error = xwimp_send_message(event, message, task);
+ if (error) {
+ LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
+
+ /* register the default bounce handler */
+ if (callback) {
+ assert(event == wimp_USER_MESSAGE_RECORDED);
+ return ro_message_register_handler(message, message->action,
+ callback);
+ }
+ return true;
+}
+
+
+/**
+ * Sends a message and registers a return route for a bounce.
+ *
+ * \param event the message event type
+ * \param message the message to register a route back for
+ * \param to_w the window to send the message to
+ * \param to_i the icon
+ * \param callback the code to call on a bounce
+ * \param to_t receives the task handle of the window's creator
+ * \return true on success, false otherwise
+ */
+bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *message,
+ wimp_w to_w, wimp_i to_i, void (*callback)(wimp_message *message),
+ wimp_t *to_t)
+{
+ os_error *error;
+
+ assert(message);
+
+ /* send a message */
+ error = xwimp_send_message_to_window(event, message, to_w, to_i, to_t);
+ if (error) {
+ LOG("xwimp_send_message_to_window: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
+
+ /* register the default bounce handler */
+ if (callback) {
+ assert(event == wimp_USER_MESSAGE_RECORDED);
+ return ro_message_register_handler(message, message->action,
+ callback);
+ }
+ return true;
+}
+
+
+/**
+ * Registers a return route for a message.
+ *
+ * This function must be called after wimp_send_message so that a
+ * valid value is present in the my_ref field.
+ *
+ * \param message the message to register a route back for
+ * \param message_code the message action code to route
+ * \param callback the code to call for a matched action
+ * \return true on success, false on memory exhaustion
+ */
+bool ro_message_register_handler(wimp_message *message,
+ unsigned int message_code,
+ void (*callback)(wimp_message *message))
+{
+ struct active_message *add;
+
+ assert(message);
+ assert(callback);
+
+ add = ro_message_add(message_code, callback);
+ if (add)
+ add->id = message->my_ref;
+ return (add != NULL);
+}
+
+
+/**
+ * Registers a route for a message code.
+ *
+ * \param message_code the message action code to route
+ * \param callback the code to call for a matched action
+ * \return true on success, false on memory exhaustion
+ */
+bool ro_message_register_route(unsigned int message_code,
+ void (*callback)(wimp_message *message))
+{
+ assert(callback);
+
+ return (ro_message_add(message_code, callback) != NULL);
+}
+
+struct active_message *ro_message_add(unsigned int message_code,
+ void (*callback)(wimp_message *message))
+{
+ struct active_message *add;
+
+ assert(callback);
+
+ add = (struct active_message *)malloc(sizeof(*add));
+ if (!add)
+ return NULL;
+ add->message_code = message_code;
+ add->id = 0;
+ add->callback = callback;
+ add->next = current_messages;
+ add->previous = NULL;
+ current_messages = add;
+ return add;
+}
+
+
+/**
+ * Attempts to route a message.
+ *
+ * \param event wimp event
+ * \param message the message to attempt to route
+ * \return true if message was routed, false otherwise
+ */
+bool ro_message_handle_message(wimp_event_no event, wimp_message *message)
+{
+ struct active_message *test;
+
+ assert(message);
+
+ if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) {
+ /* handle message acknowledgement */
+ bool handled = false;
+ int ref = message->my_ref;
+
+ if (ref == 0)
+ return false;
+
+ /* handle the message */
+ for (test = current_messages; test; test = test->next) {
+ if ((ref == test->id) &&
+ (message->action == test->message_code)) {
+ handled = true;
+ if (test->callback)
+ test->callback(message);
+ break;
+ }
+ }
+
+ /* remove all handlers for this id */
+ ro_message_free(ref);
+ return handled;
+ } else {
+ /* handle simple routing */
+ for (test = current_messages; test; test = test->next) {
+ if ((test->id == 0) &&
+ (message->action == test->message_code)) {
+ test->callback(message);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void ro_message_free(int ref)
+{
+ struct active_message *test;
+ struct active_message *next = current_messages;
+
+ while ((test = next)) {
+ next = test->next;
+ if (ref == test->id) {
+ if (test->previous)
+ test->previous->next = test->next;
+ if (test->next)
+ test->next->previous = test->previous;
+ if (current_messages == test)
+ current_messages = test->next;
+ free(test);
+ }
+ }
+}