Add missing file.
git-svn-id: svn://localhost/ardour2/branches/3.0@12280 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
32bed9aaf0
commit
5bbbc98533
298
libs/pbd/pbd/signals.py
Normal file
298
libs/pbd/pbd/signals.py
Normal file
@ -0,0 +1,298 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2009-2012 Paul Davis
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
|
||||
#
|
||||
# This file generates the header signals_generated.h, which
|
||||
# will be put in build/libs/pbd/pbd by waf.
|
||||
#
|
||||
# It is probably easier to read build/libs/pbd/pbd/signals_generated.h
|
||||
# than this if you want to read the code!
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print 'Syntax: %s <path>' % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
f = open(sys.argv[1], 'w')
|
||||
|
||||
print >>f,"/** THIS FILE IS AUTOGENERATED by signals.py: CHANGES WILL BE LOST */\n\n"
|
||||
|
||||
# Produce a comma-separated string from a list of substrings,
|
||||
# giving an optional prefix to each substring
|
||||
def comma_separated(n, prefix = ""):
|
||||
r = ""
|
||||
for i in range(0, len(n)):
|
||||
if i > 0:
|
||||
r += ", "
|
||||
r += "%s%s" % (prefix, n[i])
|
||||
return r
|
||||
|
||||
# Generate one SignalN class definition
|
||||
# @param f File to write to
|
||||
# @param n Number of parameters
|
||||
# @param v True to specialize the template for a void return type
|
||||
def signal(f, n, v):
|
||||
|
||||
# The parameters in the form A1, A2, A3, ...
|
||||
An = []
|
||||
for i in range(0, n):
|
||||
An.append("A%d" % (i + 1))
|
||||
|
||||
# The parameters in the form A1 a1, A2 a2, A3 a3, ...
|
||||
Anan = []
|
||||
for a in An:
|
||||
Anan.append('%s %s' % (a, a.lower()))
|
||||
|
||||
# The parameters in the form a1, a2, a3, ...
|
||||
an = []
|
||||
for a in An:
|
||||
an.append(a.lower())
|
||||
|
||||
if v:
|
||||
print >>f,"template <%s>" % comma_separated(An, "typename ")
|
||||
print >>f,"class Signal%d<%s> : public SignalBase" % (n, comma_separated(["void"] + An))
|
||||
else:
|
||||
print >>f,"template <%s>" % comma_separated(["R"] + An + ["C = OptionalLastValue<R> "], "typename ")
|
||||
print >>f,"class Signal%d : public SignalBase" % n
|
||||
|
||||
print >>f,"{"
|
||||
print >>f,"public:"
|
||||
print >>f,""
|
||||
if v:
|
||||
print >>f,"\ttypedef boost::function<void(%s)> slot_function_type;" % comma_separated(An)
|
||||
print >>f,"\ttypedef void result_type;"
|
||||
else:
|
||||
print >>f,"\ttypedef boost::function<R(%s)> slot_function_type;" % comma_separated(An)
|
||||
print >>f,"\ttypedef boost::optional<R> result_type;"
|
||||
|
||||
print >>f,""
|
||||
|
||||
print >>f,"private:"
|
||||
|
||||
print >>f,"""
|
||||
typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
|
||||
Slots _slots;
|
||||
"""
|
||||
|
||||
print >>f,"public:"
|
||||
print >>f,""
|
||||
print >>f,"\t~Signal%d () {" % n,
|
||||
|
||||
print >>f,"""
|
||||
boost::mutex::scoped_lock lm (_mutex);
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
|
||||
for (typename Slots::iterator i = _slots.begin(); i != _slots.end(); ++i) {
|
||||
#else
|
||||
for (Slots::iterator i = _slots.begin(); i != _slots.end(); ++i) {
|
||||
#endif
|
||||
i->first->signal_going_away ();
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
if n == 0:
|
||||
p = ""
|
||||
q = ""
|
||||
else:
|
||||
p = ", %s" % comma_separated(Anan)
|
||||
q = ", %s" % comma_separated(an)
|
||||
|
||||
print >>f,"\tstatic void compositor (typename boost::function<void(%s)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir%s) {" % (comma_separated(An), p)
|
||||
print >>f,"\t\tevent_loop->call_slot (ir, boost::bind (f%s));" % q
|
||||
print >>f,"\t}"
|
||||
|
||||
print >>f,"""
|
||||
|
||||
/** Arrange for @a slot to be executed whenever this signal is emitted.
|
||||
Store the connection that represents this arrangement in @a c.
|
||||
|
||||
NOTE: @a slot will be executed in the same thread that the signal is
|
||||
emitted in.
|
||||
*/
|
||||
|
||||
void connect_same_thread (ScopedConnection& c, const slot_function_type& slot) {
|
||||
c = _connect (slot);
|
||||
}
|
||||
|
||||
/** Arrange for @a slot to be executed whenever this signal is emitted.
|
||||
Add the connection that represents this arrangement to @a clist.
|
||||
|
||||
NOTE: @a slot will be executed in the same thread that the signal is
|
||||
emitted in.
|
||||
*/
|
||||
|
||||
void connect_same_thread (ScopedConnectionList& clist, const slot_function_type& slot) {
|
||||
clist.add_connection (_connect (slot));
|
||||
}
|
||||
|
||||
/** Arrange for @a slot to be executed in the context of @a event_loop
|
||||
whenever this signal is emitted. Add the connection that represents
|
||||
this arrangement to @a clist.
|
||||
|
||||
If the event loop/thread in which @a slot will be executed will
|
||||
outlive the lifetime of any object referenced in @a slot,
|
||||
then an InvalidationRecord should be passed, allowing
|
||||
any request sent to the @a event_loop and not executed
|
||||
before the object is destroyed to be marked invalid.
|
||||
|
||||
"outliving the lifetime" doesn't have a specific, detailed meaning,
|
||||
but is best illustrated by two contrasting examples:
|
||||
|
||||
1) the main GUI event loop/thread - this will outlive more or
|
||||
less all objects in the application, and thus when arranging for
|
||||
@a slot to be called in that context, an invalidation record is
|
||||
highly advisable.
|
||||
|
||||
2) a secondary event loop/thread which will be destroyed along
|
||||
with the objects that are typically referenced by @a slot.
|
||||
Assuming that the event loop is stopped before the objects are
|
||||
destroyed, there is no reason to pass in an invalidation record,
|
||||
and MISSING_INVALIDATOR may be used.
|
||||
*/
|
||||
|
||||
void connect (ScopedConnectionList& clist,
|
||||
PBD::EventLoop::InvalidationRecord* ir,
|
||||
const slot_function_type& slot,
|
||||
PBD::EventLoop* event_loop) {
|
||||
|
||||
if (ir) {
|
||||
ir->event_loop = event_loop;
|
||||
}
|
||||
"""
|
||||
u = []
|
||||
for i in range(0, n):
|
||||
u.append("_%d" % (i + 1))
|
||||
|
||||
if n == 0:
|
||||
p = ""
|
||||
else:
|
||||
p = ", %s" % comma_separated(u)
|
||||
|
||||
print >>f,"\t\tclist.add_connection (_connect (boost::bind (&compositor, slot, event_loop, ir%s)));" % p
|
||||
|
||||
print >>f,"""
|
||||
}
|
||||
|
||||
/** See notes for the ScopedConnectionList variant of this function. This
|
||||
* differs in that it stores the connection to the signal in a single
|
||||
* ScopedConnection rather than a ScopedConnectionList.
|
||||
*/
|
||||
|
||||
void connect (ScopedConnection& c,
|
||||
PBD::EventLoop::InvalidationRecord* ir,
|
||||
const slot_function_type& slot,
|
||||
PBD::EventLoop* event_loop) {
|
||||
|
||||
if (ir) {
|
||||
ir->event_loop = event_loop;
|
||||
}
|
||||
"""
|
||||
print >>f,"\t\tc = _connect (boost::bind (&compositor, slot, event_loop, ir%s));" % p
|
||||
print >>f,"\t}"
|
||||
|
||||
print >>f,"""
|
||||
/** Emit this signal. This will cause all slots connected to it be executed
|
||||
in the order that they were connected (cross-thread issues may alter
|
||||
the precise execution time of cross-thread slots).
|
||||
*/
|
||||
"""
|
||||
|
||||
if v:
|
||||
print >>f,"\tvoid operator() (%s)" % comma_separated(Anan)
|
||||
else:
|
||||
print >>f,"\ttypename C::result_type operator() (%s)" % comma_separated(Anan)
|
||||
print >>f,"\t{"
|
||||
print >>f,"\t\tSlots s;"
|
||||
print >>f,"\t\t{"
|
||||
print >>f,"\t\t\tboost::mutex::scoped_lock lm (_mutex);"
|
||||
print >>f,"\t\t\ts = _slots;"
|
||||
print >>f,"\t\t}"
|
||||
if not v:
|
||||
print >>f,"\t\tstd::list<R> r;"
|
||||
if n == 0 and v:
|
||||
print >>f,"""
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
|
||||
for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
|
||||
#else
|
||||
for (Slots::iterator i = s.begin(); i != s.end(); ++i) {
|
||||
#endif
|
||||
"""
|
||||
else:
|
||||
print >>f,"\t\tfor (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {"
|
||||
|
||||
print >>f,"""
|
||||
bool still_there = false;
|
||||
{
|
||||
boost::mutex::scoped_lock lm (_mutex);
|
||||
still_there = _slots.find (i->first) != _slots.end ();
|
||||
}
|
||||
|
||||
if (still_there) {"""
|
||||
if v:
|
||||
print >>f,"\t\t\t\t(i->second)(%s);" % comma_separated(an)
|
||||
else:
|
||||
print >>f,"\t\t\t\tr.push_back ((i->second)(%s));" % comma_separated(an)
|
||||
print >>f,"\t\t\t}"
|
||||
print >>f,"\t\t}"
|
||||
if not v:
|
||||
print >>f,"\t\tC c;"
|
||||
print >>f,"\t\treturn c (r.begin(), r.end());"
|
||||
print >>f,"\t}"
|
||||
|
||||
print >>f,"""
|
||||
bool empty () {
|
||||
boost::mutex::scoped_lock lm (_mutex);
|
||||
return _slots.empty ();
|
||||
}
|
||||
"""
|
||||
|
||||
if v:
|
||||
tp = comma_separated(["void"] + An)
|
||||
else:
|
||||
tp = comma_separated(["R"] + An + ["C"])
|
||||
|
||||
print >>f,""
|
||||
print >>f,"private:"
|
||||
print >>f,""
|
||||
print >>f,"\tfriend class Connection;"
|
||||
|
||||
print >>f,"""
|
||||
boost::shared_ptr<Connection> _connect (slot_function_type f)
|
||||
{
|
||||
boost::shared_ptr<Connection> c (new Connection (this));
|
||||
boost::mutex::scoped_lock lm (_mutex);
|
||||
_slots[c] = f;
|
||||
return c;
|
||||
}
|
||||
"""
|
||||
|
||||
print >>f,"""
|
||||
void disconnect (boost::shared_ptr<Connection> c)
|
||||
{
|
||||
boost::mutex::scoped_lock lm (_mutex);
|
||||
_slots.erase (c);
|
||||
}
|
||||
};
|
||||
"""
|
||||
|
||||
for i in range(0, 6):
|
||||
signal(f, i, False)
|
||||
signal(f, i, True)
|
Loading…
Reference in New Issue
Block a user