event_manager.c 3.92 KB
#include <scot/event_sink.h>
#include <scot/event_source.h>
#include <scot/event.h>
#include <scot/exception.h>

#define GEN_LOCAL
#include <scot/queue.h>
#include <scot/list.h>
#undef  GEN_LOCAL

/* 
struct scot_event_sink_event_wrapper
{
	struct scot_event_source es;
	union scot_event_u       e;
};

typedef struct scot_event_sink_event_wrapper scot_esew_t;

GEN_QUEUE (scot_esew_t);
*/

typedef struct scot_event_sink scot_event_sink_t;
GEN_LIST (scot_event_sink_t);

typedef struct scot_event_source scot_event_source_t;
GEN_LIST (scot_event_source_t);

struct scot_event_manager
{
	list_scot_event_sink_t_node_t *   sinks;
	list_scot_event_source_t_node_t * sources;
};


static
int
scot_event_source_compare_by_group_no (
		const struct scot_event_source * a,
		const struct scot_event_source * b)
{
	return (a->group_no==b->group_no)?0:(a->group_no<b->group_no)?-1:1;
};

void
scot_event_manager_register_source (
		struct scot_event_manager * m,
		struct scot_event_source *  es)
{
	struct scot_event_manager_src_cb_map * s_cb_map;

	if (scot_event_source_set_manager (es, m) != 0)
		THROW (EXC (EXC_ERROR, 1, "source already registered within other "
		                          "manager."));

	if (list_scot_event_source_t_find (m->sources, es))
		/* well, this source is already registered within this manager */
	{
		THROW (EXC (EXC_WARNING, 1, "event source already registered within "
		                            "this manager."));
		return 0;
	}

	list_scot_event_source_t_node_t_set_cmp (
			scot_event_source_compare_by_group_no);
	if (list_scot_event_source_t_find (m->sources, es))
		/* an event source of the same group is already registered within
		 * this manager */
	{
		THROW (EXC (EXC_WARNING, 1, "another event source of the same group "
											 "is already registered within this "
											 "manager."));
		return 0;
	}
	list_scot_event_source_t_node_t_set_cmp (
			list_scot_event_source_t_default_cmp);

	list_scot_event_source_t_add (m->sources, es);
}

void
scot_event_manager_register_sink (
		struct scot_event_manager * m,
		struct scot_event_sink *    es)
{
	if (scot_event_sink_set_manager (es, m) != 0)
		THROW (EXC (EXC_ERROR, 2, "Sink already registered within other "
		                          "manager."));
	list_scot_event_sink_t_add (m->sinks, s_cb_map);
}

void
scot_event_manager_call_cb (
		struct scot_event_manager * m,
		struct scot_event_source *  es,
		struct scot_event *         e)
{
	list_scot_emscm_t_node_t * emscm_node = m->src_cb;

	while (! list_scot_emscm_t_eol (m->src_cb, emscm_node))
	{
		struct scot_event_manager_src_cb_map * scbm;

		emscm_node = list_scot_emscm_t_next    (emscm_node);
		scbm       = list_scot_emscm_t_retrive (emscm_node);

		if (scbm->source == es)
		{
			scbm->cb (e);
			return;
		}
	}
}

void
scot_event_manager_dispatch_event (
		struct scot_event_manager * m,
		struct scot_event *         e,
		struct scot_event_source *  src,
		int                         mask)
{
	list_event_sink_t_node_t * es_node = m->sinks;
	int dipatched = 0;

	while (! list_scot_event_sink_t_node_t_eol (m->sinks, es_node))
	{
		struct scot_event_sink * es;
		int i;

		es_node = list_scot_event_sink_t_next    (es_node);
		es      = list_scot_event_sink_t_retrive (es_node);

		for (i=0; i<MAX_EVENT_GROUP && es->src[i]!=0; i++)
		{
			if (es->src[i] == scot_event_get_src (e) &&
			    es->mask[i] & scot_event_get_mask (e) != 0)
			{
				/* Im folgenden sollte das nicht e sondern halt irgend eine
				 * art wrapper sein aus dem auch die gruppe und maske 
				 * des events hervorgeht.
				 * sonst wird es unmöglich eine brauchbare Notice zu schicken
				 * wenn das event abgearbeitet wurde. */
				scot_event_sink_put_event (es, e);
				dispatched = 1;
			}
		}
	}

	/* wenn sich keine sink für das event interessiert hat. */
	if (dispatched == 0)
	{
		/* einen etwaigen callback aufrufen... */
		scot_event_manager_call_bc (m, get_source from event(e), e);
		/* resourcen des events freigeben... */
		scot_event_free (e);
	}
}