summaryrefslogtreecommitdiff
path: root/dnn/Trigger.cc
blob: f749b7de39049947fb82ebcd28780926f319c995 (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 *	DNN - Data News Network
 *
 *	by Stephane Chatty
 *
 *	Copyright 1993-1995
 *	Centre d'Etudes de la Navigation Aerienne (CENA)
 *
 *	Event triggers.
 *
 *	$Id$
 *	$CurLog$
 */

#include "Trigger.h"
#include "Reaction.h"
#include "Criterion.h"

/*?class IvlTrigger
\typ{IvlTrigger}s are the core of event detection and emission. The presence of a trigger
(generally in a sensor) determines whether a certain situation, or the reception
of an event from the underlying window system, should provoke the emission of an event.
Each trigger holds a list of reactions (of type \typ{IvlBaseReaction}). These reactions will
receive all the events whose creation and emission was caused by the presence of
the trigger.
?*/

/*?
Create a trigger with an empty list of associated reaction.
?*/
IvlTrigger :: IvlTrigger ()
: FirstSubscribers (),
  LastSubscribers (),
  Subscribers (),
  Grabs (),
  Criteria ()
{
}

/*?nodoc?*/
IvlTrigger :: ~IvlTrigger ()
{
	/* Force reactions to unsubscribe.
	    We should take care of conditions when destructor is called
	    during iteration */

	IvlListIterOf <IvlBaseReaction> ri  = FirstSubscribers;
	while (++ri)
		(*ri)->Forget (*this);
	ri = Subscribers;
	while (++ri)
		(*ri)->Forget (*this);
	ri = LastSubscribers;
	while (++ri)
		(*ri)->Forget (*this);
	ri = Grabs;
	while (++ri)
		(*ri)->Forget (*this);
}

/*?nextdoc?*/
void
IvlTrigger :: Subscribe (IvlBaseReaction& a, REL_PRIORITY p)
{
	switch (p) {
	case isFirstPriority:
		FirstSubscribers.Append (&a);
		break;
	case isNormalPriority:
		Subscribers.Append (&a);
		break;
	case isLastPriority:
		LastSubscribers.Prepend (&a);
		break;
	}
}

/*?
Add (resp. Remove) a reaction to (resp. from) the list of reactions that should receive
events caused by this trigger.
?*/
void
IvlTrigger :: Unsubscribe (IvlBaseReaction& a)
{
	FirstSubscribers.Remove (&a);
	Subscribers.Remove (&a);
	LastSubscribers.Remove (&a);
	Grabs.Remove (&a);
}

/*?nextdoc?*/
void
IvlTrigger :: Grab (IvlBaseReaction& a)
{
	Grabs.Prepend (&a);
}

/*?
Add (resp. Remove) a reaction onto (resp. from) the stack of reactions that preempt
events caused by this trigger.
?*/
void
IvlTrigger :: Release (IvlBaseReaction& a)
{
	Grabs.Remove (&a);
}

#if 0
void
IvlTrigger :: Circulate (IvlBaseReaction& r, REL_POS pos, IvlBaseReaction* ref)
{

	if (Subscribers.Remove (&r)) {
		/* find the predecessor of ref */
		IvlListIterOf <IvlBaseReaction> lc = Subscribers;
		while (++lc && (*lc != ref))
			;
		/* NOW, lc is on ref, or at the end if ref == 0 */
		if (pos == isBefore)
			Subscribers.InsertBefore (lc, &r);
		else
			Subscribers.InsertAfter (lc, &r);
	}

}
#endif

/*?
Have a trigger dispatch the event \var{ev} to its associated reactions.
?*/
void
IvlTrigger :: Dispatch (IvlEvent& ev)
{
	IvlBaseReaction* r = Grabs.First ();
	if (r) {
		r->Manage (ev);
	} else {
		/* calls to Manage may result in changes in Subscribers; let's make a safe copy */
		IvlListOf <IvlBaseReaction> first_subscribers = FirstSubscribers;
		IvlListOf <IvlBaseReaction> subscribers = Subscribers;
		IvlListOf <IvlBaseReaction> last_subscribers = LastSubscribers;

		IvlListIterOf <IvlBaseReaction> s = first_subscribers;
		while (++s)
#ifdef CRITERIA_IN_REACTIONS
			if ((*s)->Check (ev))
#endif
			(*s)->Manage (ev);

		s = subscribers;
		while (++s)
#ifdef CRITERIA_IN_REACTIONS
			if ((*s)->Check (ev))
#endif
			(*s)->Manage (ev);

		s = last_subscribers;
		while (++s)
#ifdef CRITERIA_IN_REACTIONS
			if ((*s)->Check (ev))
#endif
			(*s)->Manage (ev);
	}
}

bool
IvlTrigger :: Check (IvlEvent& ev)
{
	IvlListIterOf <IvlBaseCriterion> c = Criteria;
	while (++c)
		if (!(*c)->Test (ev))
			return false;

#ifdef CRITERIA_IN_REACTIONS
	IvlListIterOf <IvlBaseReaction> ri  = FirstSubscribers;
	while (++ri)
		if ((*ri)->Check (ev))
			return true;
	ri = Subscribers;
	while (++ri)
		if ((*ri)->Check (ev))
			return true;
	ri = LastSubscribers;
	while (++ri)
		if ((*ri)->Check (ev))
			return true;
	return false;
#else
	return true;
#endif
}