summaryrefslogtreecommitdiff
path: root/src/FbTk/Signal.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk/Signal.hh')
-rw-r--r--src/FbTk/Signal.hh218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/FbTk/Signal.hh b/src/FbTk/Signal.hh
new file mode 100644
index 0000000..768ca90
--- /dev/null
+++ b/src/FbTk/Signal.hh
@@ -0,0 +1,218 @@
1// Signal.hh for FbTk, Fluxbox Toolkit
2// Copyright (c) 2008 Henrik Kinnunen (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifndef FBTK_SIGNAL_HH
23#define FBTK_SIGNAL_HH
24
25#include "Slot.hh"
26#include <list>
27#include <vector>
28
29namespace FbTk {
30
31/// \namespace Implementation details for signals, do not use anything in this namespace
32namespace SigImpl {
33
34/**
35 * Parent class for all \c Signal[0...*] classes.
36 * It handles the disconnect and holds all the slots. The connect must be
37 * handled by the child class so it can do the type checking.
38 */
39class SignalHolder {
40public:
41 /// Do not use this type outside this class
42 typedef std::list<SlotHolder> SlotList;
43
44 typedef SlotList::iterator Iterator;
45 typedef Iterator SlotID;
46 typedef SlotList::const_iterator ConstIterator;
47
48 /// Remove a specific slot \c id from this signal
49 void disconnect(SlotID slotIt) {
50 m_slots.erase( slotIt );
51 }
52
53
54 /// Removes all slots connected to this
55 void clear() {
56 m_slots.clear();
57 }
58
59protected:
60 ConstIterator begin() const { return m_slots.begin(); }
61 ConstIterator end() const { return m_slots.end(); }
62
63 Iterator begin() { return m_slots.begin(); }
64 Iterator end() { return m_slots.end(); }
65
66 /// Connect a slot to this signal. Must only be called by child classes.
67 SlotID connect(const SlotHolder& slot) {
68 return m_slots.insert(m_slots.end(), slot);
69 }
70
71private:
72 SlotList m_slots; ///< all slots connected to a signal
73};
74
75/// Signal with no argument
76template <typename ReturnType>
77class Signal0: public SignalHolder {
78public:
79 typedef Slot0<ReturnType> SlotType;
80
81 void emit() {
82 for ( Iterator it = begin(); it != end(); ++it ) {
83 static_cast<SlotType&>(*it)();
84 }
85 }
86
87 SlotID connect(const SlotType& slot) {
88 return SignalHolder::connect(slot);
89
90 }
91};
92
93/// Signal with one argument
94template <typename ReturnType, typename Arg1>
95class Signal1: public SignalHolder {
96public:
97 typedef Slot1<ReturnType, Arg1> SlotType;
98
99 void emit(Arg1 arg) {
100 for ( Iterator it = begin(); it != end(); ++it ) {
101 static_cast<SlotType&>(*it)(arg);
102 }
103 }
104
105 SlotID connect(const SlotType& slot) {
106 return SignalHolder::connect(slot);
107 }
108
109};
110
111/// Signal with two arguments
112template <typename ReturnType, typename Arg1, typename Arg2>
113class Signal2: public SignalHolder {
114public:
115 typedef Slot2<ReturnType, Arg1, Arg2> SlotType;
116
117 void emit(Arg1 arg1, Arg2 arg2) {
118 for ( Iterator it = begin(); it != end(); ++it ) {
119 static_cast<SlotType&>(*it)(arg1, arg2);
120 }
121 }
122
123 SlotID connect(const SlotType& slot) {
124 return SignalHolder::connect(slot);
125 }
126};
127
128/// Signal with three arguments
129template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
130class Signal3: public SignalHolder {
131public:
132 typedef Slot3<ReturnType, Arg1, Arg2, Arg3> SlotType;
133
134 void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
135 for ( Iterator it = begin(); it != end(); ++it ) {
136 static_cast<SlotType&>(*it)(arg1, arg2, arg3);
137 }
138 }
139
140 SlotID connect(const SlotType& slot) {
141 return SignalHolder::connect(slot);
142 }
143
144};
145
146struct EmptyArg {};
147
148} // namespace SigImpl
149
150
151/// Specialization for three arguments.
152template <typename ReturnType,
153 typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg >
154class Signal: public SigImpl::Signal3< ReturnType, Arg1, Arg2, Arg3 > {
155public:
156};
157
158/// Specialization for two arguments.
159template <typename ReturnType, typename Arg1, typename Arg2>
160class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::Signal2< ReturnType, Arg1, Arg2 > {
161public:
162};
163
164/// Specialization for one argument.
165template <typename ReturnType, typename Arg1>
166class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal1< ReturnType, Arg1 > {
167public:
168};
169
170/// Specialization for no argument.
171template <typename ReturnType>
172class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal0< ReturnType > {
173public:
174};
175
176/**
177 * Tracks a signal during it's life time. All signals connected using \c
178 * SignalTracker::join will be erased when this instance dies.
179 */
180class SignalTracker {
181public:
182 /// Internal type, do not use.
183 typedef std::list< std::pair< SigImpl::SignalHolder*, SigImpl::SignalHolder::SlotID > > Connections;
184 typedef Connections::iterator TrackID; ///< \c ID type for join/leave.
185
186 ~SignalTracker() {
187 // disconnect all connections
188 for ( Connections::iterator conIt = m_connections.begin();
189 conIt != m_connections.end(); ) {
190 conIt->first->disconnect( conIt->second );
191 conIt = m_connections.erase( conIt );
192 }
193 }
194
195 /// Starts tracking a signal.
196 /// @return A tracking ID ( not unique )
197 template <typename Signal, typename Functor>
198 TrackID join(Signal& sig, const Functor& functor) {
199 return
200 m_connections.insert(m_connections.end(),
201 Connections::value_type(&sig, sig.connect(functor)));
202 }
203
204 /// Leave tracking for a signal
205 /// @param id the \c id from the previous \c join
206 void leave(TrackID id) {
207 m_connections.erase(id);
208 }
209
210private:
211 /// holds all connections to different signals and slots.
212 Connections m_connections;
213};
214
215
216} // namespace FbTk
217
218#endif // FBTK_SIGNAL_HH