ardour
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
libs
pbd
pbd
signals.py
Go to the documentation of this file.
1
#!/usr/bin/python
2
#
3
# Copyright (C) 2009-2012 Paul Davis
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
#
19
20
#
21
# This file generates the header signals_generated.h, which
22
# will be put in build/libs/pbd/pbd by waf.
23
#
24
# It is probably easier to read build/libs/pbd/pbd/signals_generated.h
25
# than this if you want to read the code!
26
#
27
28
from
__future__
import
print_function
29
import
sys
30
31
if
len(sys.argv) < 2:
32
print(
'Syntax: %s <path>'
% sys.argv[0])
33
sys.exit(1)
34
35
f = open(sys.argv[1],
'w'
)
36
37
print(
"/** THIS FILE IS AUTOGENERATED by signals.py: CHANGES WILL BE LOST */\n"
, file=f)
38
39
# Produce a comma-separated string from a list of substrings,
40
# giving an optional prefix to each substring
41
def
comma_separated
(n, prefix = ""):
42
r =
""
43
for
i
in
range(0, len(n)):
44
if
i > 0:
45
r +=
", "
46
r +=
"%s%s"
% (prefix, n[i])
47
return
r
48
49
# Generate one SignalN class definition
50
# @param f File to write to
51
# @param n Number of parameters
52
# @param v True to specialize the template for a void return type
53
def
signal
(f, n, v):
54
55
# The parameters in the form A1, A2, A3, ...
56
An = []
57
for
i
in
range(0, n):
58
An.append(
"A%d"
% (i + 1))
59
60
# The parameters in the form A1 a1, A2 a2, A3 a3, ...
61
Anan = []
62
for
a
in
An:
63
Anan.append(
'%s %s'
% (a, a.lower()))
64
65
# The parameters in the form a1, a2, a3, ...
66
an = []
67
for
a
in
An:
68
an.append(a.lower())
69
70
# If the template is fully specialized, use of typename SomeTypedef::iterator is illegal
71
# in c++03 (should use just SomeTypedef::iterator) [although use of typename is ok in c++0x]
72
# http://stackoverflow.com/questions/6076015/typename-outside-of-template
73
if
n == 0
and
v:
74
typename =
""
75
else
:
76
typename =
"typename "
77
78
if
v:
79
print(
"/** A signal with %d parameters (specialisation for a void return) */"
% n, file=f)
80
else
:
81
print(
"/** A signal with %d parameters */"
% n, file=f)
82
if
v:
83
print(
"template <%s>"
%
comma_separated
(An,
"typename "
), file=f)
84
print(
"class Signal%d<%s> : public SignalBase"
% (n,
comma_separated
([
"void"
] + An)), file=f)
85
else
:
86
print(
"template <%s>"
%
comma_separated
([
"
R"] + An + ["
C = OptionalLastValue<R> "], "typename "), file=f)
87
print(
"class Signal%d : public SignalBase"
% n, file=f)
88
89
print(
"{"
, file=f)
90
print(
"public:"
, file=f)
91
print(
""
, file=f)
92
if
v:
93
print(
"\ttypedef boost::function<void(%s)> slot_function_type;"
%
comma_separated
(An), file=f)
94
print(
"\ttypedef void result_type;"
, file=f)
95
else
:
96
print(
"\ttypedef boost::function<R(%s)> slot_function_type;"
%
comma_separated
(An), file=f)
97
print(
"\ttypedef boost::optional<R> result_type;"
, file=f)
98
99
print(
""
, file=f)
100
101
print(
"private:"
, file=f)
102
103
print(
"""
104
/** The slots that this signal will call on emission */
105
typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
106
Slots _slots;
107
"""
, file=f)
108
109
print(
"public:"
, file=f)
110
print(
""
, file=f)
111
print(
"\t~Signal%d () {"
% n, file=f)
112
113
print(
"\t\tGlib::Threads::Mutex::Lock lm (_mutex);"
, file=f)
114
print(
"\t\t/* Tell our connection objects that we are going away, so they don't try to call us */"
, file=f)
115
print(
"\t\tfor (%sSlots::const_iterator i = _slots.begin(); i != _slots.end(); ++i) {"
% typename, file=f)
116
117
print(
"\t\t\ti->first->signal_going_away ();"
, file=f)
118
print(
"\t\t}"
, file=f)
119
print(
"\t}"
, file=f)
120
print(
""
, file=f)
121
122
if
n == 0:
123
p =
""
124
q =
""
125
else
:
126
p =
", %s"
%
comma_separated
(Anan)
127
q =
", %s"
%
comma_separated
(an)
128
129
print(
"\tstatic void compositor (%sboost::function<void(%s)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir%s) {"
% (typename,
comma_separated
(An), p), file=f)
130
print(
"\t\tevent_loop->call_slot (ir, boost::bind (f%s));"
% q, file=f)
131
print(
"\t}"
, file=f)
132
133
print(
"""
134
/** Arrange for @a slot to be executed whenever this signal is emitted.
135
Store the connection that represents this arrangement in @a c.
136
137
NOTE: @a slot will be executed in the same thread that the signal is
138
emitted in.
139
*/
140
141
void connect_same_thread (ScopedConnection& c, const slot_function_type& slot) {
142
c = _connect (slot);
143
}
144
145
/** Arrange for @a slot to be executed whenever this signal is emitted.
146
Add the connection that represents this arrangement to @a clist.
147
148
NOTE: @a slot will be executed in the same thread that the signal is
149
emitted in.
150
*/
151
152
void connect_same_thread (ScopedConnectionList& clist, const slot_function_type& slot) {
153
clist.add_connection (_connect (slot));
154
}
155
156
/** Arrange for @a slot to be executed in the context of @a event_loop
157
whenever this signal is emitted. Add the connection that represents
158
this arrangement to @a clist.
159
160
If the event loop/thread in which @a slot will be executed will
161
outlive the lifetime of any object referenced in @a slot,
162
then an InvalidationRecord should be passed, allowing
163
any request sent to the @a event_loop and not executed
164
before the object is destroyed to be marked invalid.
165
166
"outliving the lifetime" doesn't have a specific, detailed meaning,
167
but is best illustrated by two contrasting examples:
168
169
1) the main GUI event loop/thread - this will outlive more or
170
less all objects in the application, and thus when arranging for
171
@a slot to be called in that context, an invalidation record is
172
highly advisable.
173
174
2) a secondary event loop/thread which will be destroyed along
175
with the objects that are typically referenced by @a slot.
176
Assuming that the event loop is stopped before the objects are
177
destroyed, there is no reason to pass in an invalidation record,
178
and MISSING_INVALIDATOR may be used.
179
*/
180
181
void connect (ScopedConnectionList& clist,
182
PBD::EventLoop::InvalidationRecord* ir,
183
const slot_function_type& slot,
184
PBD::EventLoop* event_loop) {
185
186
if (ir) {
187
ir->event_loop = event_loop;
188
}
189
"""
, file=f)
190
u = []
191
for
i
in
range(0, n):
192
u.append(
"_%d"
% (i + 1))
193
194
if
n == 0:
195
p =
""
196
else
:
197
p =
", %s"
%
comma_separated
(u)
198
199
print(
"\t\tclist.add_connection (_connect (boost::bind (&compositor, slot, event_loop, ir%s)));"
% p, file=f)
200
201
print(
"""
202
}
203
204
/** See notes for the ScopedConnectionList variant of this function. This
205
* differs in that it stores the connection to the signal in a single
206
* ScopedConnection rather than a ScopedConnectionList.
207
*/
208
209
void connect (ScopedConnection& c,
210
PBD::EventLoop::InvalidationRecord* ir,
211
const slot_function_type& slot,
212
PBD::EventLoop* event_loop) {
213
214
if (ir) {
215
ir->event_loop = event_loop;
216
}
217
"""
, file=f)
218
print(
"\t\tc = _connect (boost::bind (&compositor, slot, event_loop, ir%s));"
% p, file=f)
219
print(
"\t}"
, file=f)
220
221
print(
"""
222
/** Emit this signal. This will cause all slots connected to it be executed
223
in the order that they were connected (cross-thread issues may alter
224
the precise execution time of cross-thread slots).
225
*/
226
"""
, file=f)
227
228
if
v:
229
print(
"\tvoid operator() (%s)"
%
comma_separated
(Anan), file=f)
230
else
:
231
print(
"\ttypename C::result_type operator() (%s)"
%
comma_separated
(Anan), file=f)
232
print(
"\t{"
, file=f)
233
print(
"\t\t/* First, take a copy of our list of slots as it is now */"
, file=f)
234
print(
""
, file=f)
235
print(
"\t\tSlots s;"
, file=f)
236
print(
"\t\t{"
, file=f)
237
print(
"\t\t\tGlib::Threads::Mutex::Lock lm (_mutex);"
, file=f)
238
print(
"\t\t\ts = _slots;"
, file=f)
239
print(
"\t\t}"
, file=f)
240
print(
""
, file=f)
241
if
not
v:
242
print(
"\t\tstd::list<R> r;"
, file=f)
243
print(
"\t\tfor (%sSlots::const_iterator i = s.begin(); i != s.end(); ++i) {"
% typename, file=f)
244
print(
"""
245
/* We may have just called a slot, and this may have resulted in
246
disconnection of other slots from us. The list copy means that
247
this won't cause any problems with invalidated iterators, but we
248
must check to see if the slot we are about to call is still on the list.
249
*/
250
bool still_there = false;
251
{
252
Glib::Threads::Mutex::Lock lm (_mutex);
253
still_there = _slots.find (i->first) != _slots.end ();
254
}
255
256
if (still_there) {"""
, file=f)
257
if
v:
258
print(
"\t\t\t\t(i->second)(%s);"
%
comma_separated
(an), file=f)
259
else
:
260
print(
"\t\t\t\tr.push_back ((i->second)(%s));"
%
comma_separated
(an), file=f)
261
print(
"\t\t\t}"
, file=f)
262
print(
"\t\t}"
, file=f)
263
print(
""
, file=f)
264
if
not
v:
265
print(
"\t\t/* Call our combiner to do whatever is required to the result values */"
, file=f)
266
print(
"\t\tC c;"
, file=f)
267
print(
"\t\treturn c (r.begin(), r.end());"
, file=f)
268
print(
"\t}"
, file=f)
269
270
print(
"""
271
bool empty () {
272
Glib::Threads::Mutex::Lock lm (_mutex);
273
return _slots.empty ();
274
}
275
"""
, file=f)
276
277
if
v:
278
tp =
comma_separated
([
"void"
] + An)
279
else
:
280
tp =
comma_separated
([
"
R"] + An + ["
C"])
281
282
print(
"private:"
, file=f)
283
print(
""
, file=f)
284
print(
"\tfriend class Connection;"
, file=f)
285
286
print(
"""
287
boost::shared_ptr<Connection> _connect (slot_function_type f)
288
{
289
#ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
290
if (_debug_connection) {
291
PBD::stacktrace (std::cerr, 10);
292
}
293
#endif
294
boost::shared_ptr<Connection> c (new Connection (this));
295
Glib::Threads::Mutex::Lock lm (_mutex);
296
_slots[c] = f;
297
return c;
298
}"""
, file=f)
299
300
print(
"""
301
void disconnect (boost::shared_ptr<Connection> c)
302
{
303
Glib::Threads::Mutex::Lock lm (_mutex);
304
_slots.erase (c);
305
}
306
};
307
"""
, file=f)
308
309
for
i
in
range(0, 6):
310
signal
(f, i,
False
)
311
signal
(f, i,
True
)
signals.comma_separated
def comma_separated
Definition:
signals.py:41
signals.signal
def signal
Definition:
signals.py:53
Generated on Sun May 24 2015 12:15:08 for ardour by
1.8.8