1 |
/* |
/* |
2 |
$Id$ |
$Id$ |
3 |
|
|
4 |
Copyright (C) 2004 Kai Sterker <kaisterker@linuxgames.com> |
Copyright (C) 2004/2005 Kai Sterker <kaisterker@linuxgames.com> |
5 |
Part of the Adonthell Project http://adonthell.linuxgames.com |
Part of the Adonthell Project http://adonthell.linuxgames.com |
6 |
|
|
7 |
Adonthell is free software; you can redistribute it and/or modify |
Adonthell is free software; you can redistribute it and/or modify |
8 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
9 |
the Free Software Foundation; either version 2 of the License, or |
the Free Software Foundation; either version 2 of the License, or |
10 |
(at your option) any later version. |
(at your option) any later version. |
11 |
|
|
12 |
Adonthell is distributed in the hope that it will be useful, |
Adonthell is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
GNU General Public License for more details. |
16 |
|
|
17 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
18 |
along with Adonthell; if not, write to the Free Software |
along with Adonthell; if not, write to the Free Software |
19 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
*/ |
*/ |
21 |
|
|
22 |
/** |
/** |
23 |
* @file event/listener.cc |
* @file event/listener.cc |
24 |
* @author Kai Sterker <kaisterker@linuxgames.com> |
* @author Kai Sterker <kaisterker@linuxgames.com> |
25 |
* |
* |
26 |
* @brief Declares the %listener class. |
* @brief Declares the %listener class. |
27 |
* |
* |
28 |
*/ |
*/ |
29 |
|
|
30 |
#include "python/pool.h" |
#include "python/pool.h" |
31 |
#include "event/manager.h" |
#include "event/manager.h" |
32 |
#include "event/listener.h" |
#include "event/listener.h" |
33 |
|
|
34 |
using events::factory; |
using events::factory; |
35 |
using events::listener; |
using events::listener; |
36 |
|
|
37 |
// Array with callbacks to return a newly instanciated event |
// ctor |
38 |
new_event listener::instanciate_event[MAX_EVENTS]; |
listener::listener (factory *f, event *e) |
39 |
|
{ |
40 |
// ctor |
Registered = false; |
41 |
listener::listener (factory *f, event *e) |
Method = NULL; |
42 |
{ |
Args = NULL; |
43 |
Registered = false; |
Factory = f; |
44 |
Method = NULL; |
Event = e; |
45 |
Args = NULL; |
Paused = 0; |
46 |
Factory = f; |
Id = ""; |
47 |
Event = e; |
} |
48 |
Paused = 0; |
|
49 |
Id = ""; |
// destructor |
50 |
} |
listener::~listener () |
51 |
|
{ |
52 |
// destructor |
// automatically remove myself from the event manager |
53 |
listener::~listener () |
if (Registered) manager::remove (this); |
54 |
{ |
// ... and from the factory |
55 |
// automatically remove myself from the event manager |
if (Factory) Factory->remove (this); |
56 |
if (Registered) manager::remove (this); |
|
57 |
// ... and from the factory |
delete Event; |
58 |
if (Factory) Factory->remove (this); |
|
59 |
|
// we no longer use the callback |
60 |
delete Event; |
delete Method; |
61 |
|
// ... and the arguments neither |
62 |
// we no longer use the callback |
Py_XDECREF (Args); |
63 |
delete Method; |
} |
64 |
// ... and the arguments neither |
|
65 |
Py_XDECREF (Args); |
// set python method to be called when the event occurs |
66 |
} |
bool listener::connect_callback (const string & file, const string & classname, const string & callback, PyObject *args) |
67 |
|
{ |
68 |
// set python method to be called when the event occurs |
u_int16 size; |
69 |
bool listener::connect_callback (const string & file, const string & classname, const string & callback, PyObject *args) |
|
70 |
{ |
// cleanup |
71 |
u_int16 size; |
delete Method; |
72 |
|
|
73 |
// cleanup |
// just disconnect the callback |
74 |
delete Method; |
if (file == "") |
75 |
|
{ |
76 |
// just disconnect the callback |
Method = NULL; |
77 |
if (file == "") |
return false; |
78 |
{ |
} |
79 |
Method = NULL; |
|
80 |
return false; |
// create the callback |
81 |
} |
Method = python::pool::connect (EVENTS_DIR + file, classname, callback); |
82 |
|
if (!Method) |
83 |
// create the callback |
{ |
84 |
Method = python::pool::connect (EVENTS_DIR + file, classname, callback); |
fprintf (stderr, "*** listener::connect_callback: connecting callback failed!\n"); |
85 |
if (!Method) |
return false; |
86 |
{ |
} |
87 |
fprintf (stderr, "*** listener::connect_callback: connecting callback failed!\n"); |
|
88 |
return false; |
// make sure the given arguments are a tuple |
89 |
} |
if (!args || !PyTuple_Check (args)) |
90 |
|
{ |
91 |
// make sure the given arguments are a tuple |
if (args) fprintf (stderr, "*** warning: listener::connect_callback: argument must be a tuple!\n"); |
92 |
if (!args || !PyTuple_Check (args)) |
size = 2; |
93 |
{ |
} |
94 |
if (args) fprintf (stderr, "*** warning: listener::connect_callback: argument must be a tuple!\n"); |
else size = PyTuple_GET_SIZE (args) + 2; |
95 |
size = 2; |
|
96 |
} |
// keep old argument tuple, if possible |
97 |
else size = PyTuple_GET_SIZE (args) + 2; |
if (!Args || PyTuple_GET_SIZE (Args) != size) |
98 |
|
{ |
99 |
// keep old argument tuple, if possible |
// free old args |
100 |
if (!Args || PyTuple_GET_SIZE (Args) != size) |
Py_XDECREF (Args); |
101 |
{ |
|
102 |
// free old args |
// prepare callback arguments |
103 |
Py_XDECREF (Args); |
Args = PyTuple_New (size); |
104 |
|
|
105 |
// prepare callback arguments |
// first argument is the listener itself |
106 |
Args = PyTuple_New (size); |
PyTuple_SET_ITEM (Args, 0, python::pass_instance (this)); |
107 |
|
} |
108 |
// first argument is the listener itself |
|
109 |
PyTuple_SET_ITEM (Args, 0, python::pass_instance (this)); |
// second argument will be the event that triggered the callback |
110 |
} |
for (u_int16 i = 2; i < size; i++) |
111 |
|
{ |
112 |
// second argument will be the event that triggered the callback |
// copy remaining arguments, if any |
113 |
for (u_int16 i = 2; i < size; i++) |
PyObject *arg = PyTuple_GET_ITEM (args, i-2); |
114 |
{ |
Py_INCREF (arg); |
115 |
// copy remaining arguments, if any |
PyTuple_SET_ITEM (Args, i, arg); |
116 |
PyObject *arg = PyTuple_GET_ITEM (args, i-2); |
} |
117 |
Py_INCREF (arg); |
return true; |
118 |
PyTuple_SET_ITEM (Args, i, arg); |
} |
119 |
} |
|
120 |
return true; |
// execute callback for given event |
121 |
} |
s_int32 listener::raise_event (const event* evnt) |
122 |
|
{ |
123 |
// execute callback for given event |
if (Method && Event->repeat ()) |
124 |
s_int32 listener::raise_event (const event* evnt) |
{ |
125 |
{ |
// make sure that arguments remain valid while the script executes |
126 |
if (Method && Event->repeat ()) |
PyObject *args = Args; |
127 |
{ |
Py_INCREF (args); |
128 |
// make sure that arguments remain valid while the script executes |
|
129 |
PyObject *args = Args; |
// event that triggered the script is 2nd argument of callback |
130 |
Py_INCREF (args); |
PyTuple_SET_ITEM (args, 1, python::pass_instance ((event*) evnt)); |
131 |
|
|
132 |
// event that triggered the script is 2nd argument of callback |
// adjust repeat count |
133 |
PyTuple_SET_ITEM (args, 1, python::pass_instance ((event*) evnt)); |
Event->do_repeat (); |
134 |
|
|
135 |
// adjust repeat count |
// execute callback |
136 |
Event->do_repeat (); |
Method->execute (args); |
137 |
|
|
138 |
// execute callback |
// clean up |
139 |
Method->execute (args); |
Py_DECREF (PyTuple_GET_ITEM (args, 1)); |
140 |
|
Py_DECREF (args); |
141 |
// clean up |
} |
142 |
Py_DECREF (PyTuple_GET_ITEM (args, 1)); |
else |
143 |
Py_DECREF (args); |
{ |
144 |
} |
if (!Method) fprintf (stderr, "*** warning: listener::raise_event: no callback connected\n"); |
145 |
else |
return 0; |
146 |
{ |
} |
147 |
if (!Method) fprintf (stderr, "*** warning: listener::raise_event: no callback connected\n"); |
|
148 |
return 0; |
// return whether event needs be repeated or not |
149 |
} |
return Event->repeat (); |
150 |
|
} |
151 |
// return whether event needs be repeated or not |
|
152 |
return Event->repeat (); |
// disable the event temporarily |
153 |
} |
void listener::pause (const u_int16 & level) |
154 |
|
{ |
155 |
// disable the event temporarily |
if (Paused == 0) manager::remove (this); |
156 |
void listener::pause (const u_int16 & level) |
Paused += level; |
157 |
{ |
} |
158 |
if (Paused == 0) manager::remove (this); |
|
159 |
Paused += level; |
// resume a disabled event |
160 |
} |
void listener::resume () |
161 |
|
{ |
162 |
// resume a disabled event |
if (Paused == 0) |
163 |
void listener::resume () |
{ |
164 |
{ |
fprintf (stderr, "*** warning: listener::resume: listener was not paused!\n"); |
165 |
if (Paused == 0) |
if (!Registered) manager::add (this); |
166 |
{ |
} |
167 |
fprintf (stderr, "*** warning: listener::resume: listener was not paused!\n"); |
else |
168 |
if (!Registered) manager::add (this); |
{ |
169 |
} |
Paused--; |
170 |
else |
if (Paused == 0) manager::add (this); |
171 |
{ |
} |
172 |
Paused--; |
} |
173 |
if (Paused == 0) manager::add (this); |
|
174 |
} |
// save the state of the script associated with the event |
175 |
} |
void listener::put_state (base::flat & out) const |
176 |
|
{ |
177 |
// save the state of the script associated with the event |
base::flat listener; |
178 |
void listener::put_state (base::flat & out) const |
|
179 |
{ |
listener.put_string ("lid", Id); |
180 |
base::flat listener; |
listener.put_uint16 ("lps", Paused); |
181 |
|
listener.put_bool ("lmt", Method != NULL); |
182 |
listener.put_string ("lid", Id); |
|
183 |
listener.put_uint16 ("lps", Paused); |
if (Method != NULL) |
184 |
listener.put_bool ("lmt", Method != NULL); |
{ |
185 |
|
Method->put_state (listener); |
186 |
if (Method != NULL) |
python::put_tuple (Args, listener, 2); |
187 |
{ |
} |
188 |
Method->put_state (listener); |
|
189 |
python::put_tuple (Args, listener, 2); |
listener.put_bool ("lev", Event != NULL); |
190 |
} |
if (Event != NULL) Event->put_state (listener); |
191 |
|
|
192 |
listener.put_bool ("lev", Event != NULL); |
out.put_flat ("", listener); |
193 |
if (Event != NULL) Event->put_state (listener); |
} |
194 |
|
|
195 |
out.put_flat ("", listener); |
// load the state of the script associated with the event |
196 |
} |
bool listener::get_state (base::flat & in) |
197 |
|
{ |
198 |
// load the state of the script associated with the event |
Id = in.get_string ("lid"); |
199 |
bool listener::get_state (base::flat & in) |
Paused = in.get_uint16 ("lps"); |
200 |
{ |
|
201 |
Id = in.get_string ("lid"); |
// load callback |
202 |
Paused = in.get_uint16 ("lps"); |
if (in.get_bool ("lmt") == true) |
203 |
|
{ |
204 |
// load callback |
Method = new python::method (); |
205 |
if (in.get_bool ("lmt") == true) |
if (Method->get_state (in) == false) |
206 |
{ |
{ |
207 |
Method = new python::method (); |
fprintf (stderr, "*** listener::get_state: restoring callback failed!\n"); |
208 |
if (Method->get_state (in) == false) |
return false; |
209 |
{ |
} |
210 |
fprintf (stderr, "*** listener::get_state: restoring callback failed!\n"); |
|
211 |
return false; |
Args = python::get_tuple (in, 2); |
212 |
} |
PyTuple_SET_ITEM (Args, 0, python::pass_instance (this)); |
213 |
|
} |
214 |
Args = python::get_tuple (in, 2); |
|
215 |
PyTuple_SET_ITEM (Args, 0, python::pass_instance (this)); |
// load event structure |
216 |
} |
if (in.get_bool ("lev") == true) |
217 |
|
{ |
218 |
// load event structure |
std::string type = in.get_string ("etp"); |
219 |
if (in.get_bool ("lev") == true) |
|
220 |
{ |
// Instanciate an event of the given type |
221 |
u_int8 type = in.get_uint8 ("etp"); |
Event = event_type::instanciate_event (type); |
222 |
|
|
223 |
// Instanciate an event of the given type |
// try to load it |
224 |
if (type < MAX_EVENTS && instanciate_event[type] != NULL) |
if (Event == NULL || Event->get_state (in) == false) |
225 |
Event = instanciate_event[type](); |
{ |
226 |
|
fprintf (stderr, "*** listener::get_state: could not load event of type '%s'!\n", type.c_str ()); |
227 |
// try to load it |
return false; |
228 |
if (Event == NULL || Event->get_state (in) == false) |
} |
229 |
{ |
} |
230 |
fprintf (stderr, "*** listener::get_state: could not load event of type %i!\n", type); |
|
231 |
return false; |
return in.success (); |
232 |
} |
} |
233 |
} |
|
234 |
|
|
|
return in.success (); |
|
|
} |
|
|
|
|
|
// Register an event for loading |
|
|
void listener::register_event (u_int8 type, new_event e) |
|
|
{ |
|
|
if (type < MAX_EVENTS) |
|
|
instanciate_event[type] = e; |
|
|
} |
|
|
|
|