netsurf/riscos/message.c
Vincent Sanders c105738fa3 Change LOG() macro to be varadic
This changes the LOG macro to be varadic removing the need for all
callsites to have double bracketing and allows for future improvement
on how we use the logging macros.

The callsites were changed with coccinelle and the changes checked by
hand. Compile tested for several frontends but not all.

A formatting annotation has also been added which allows the compiler
to check the parameters and types passed to the logging.
2015-05-28 16:08:46 +01:00

247 lines
6.2 KiB
C

/*
* 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 "riscos/message.h"
#include "utils/log.h"
#include "utils/utils.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);
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);
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);
}
}
}