summaryrefslogtreecommitdiff
path: root/riscos/message.c
blob: 97518e9dccda673dd70ece2c6c2064005c871ec9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * 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 2006 Richard Wilson <info@tinct.net>
 */

/** \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 "netsurf/riscos/message.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/utils.h"


struct active_message {
	unsigned int message_code;
	int id;
	void (*callback)(wimp_event_no event, wimp_message *message);
	struct active_message *next;
	struct active_message *previous;
};
struct active_message *current_messages = NULL;


/**
 * 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_event_no event, wimp_message *message)) {
	os_error *error;

	/* 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;
}



/**
 * 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 messge_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_event_no event, wimp_message *message)) {
	struct active_message *add;

	assert(message);
	assert(callback);

	add = (struct active_message *)malloc(sizeof(*add));
	if (!add)
		return false;
	add->message_code = message_code;
	add->id = message->my_ref;
	add->callback = callback;
	add->next = current_messages;
	add->previous = NULL;
	current_messages = add;
	return true;
}


/**
 * Attempts to route a message.
 *
 * \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;
	struct active_message *next;
	bool handled = true;
	int ref;

	assert(message);

	/* we can't work without a reference */
	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(event, message);
			break;
		}
	}

	/* remove all handlers for this id */
	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);
		}
	}
	return handled;
}