summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Kinnunen <fluxgen@fluxbox.org>2008-09-18 20:24:35 (GMT)
committerHenrik Kinnunen <fluxgen@fluxbox.org>2008-09-18 20:24:35 (GMT)
commite4d4717703b365bc14f189bf36b3edb1e4430b90 (patch)
tree1e678e6d0569714ab8c78fa0900c18ee1bb0f10a
parent8e97963e4211963f960c52c8a8f4bf5cd135ad2f (diff)
downloadfluxbox_lack-e4d4717703b365bc14f189bf36b3edb1e4430b90.zip
fluxbox_lack-e4d4717703b365bc14f189bf36b3edb1e4430b90.tar.bz2
Added new Signal/Slot system in FbTk
This is suppose to replace the obsolete Subject/Observer classes. See the src/tests/testSignals.cc for basic usage.
-rw-r--r--ChangeLog5
-rw-r--r--src/FbTk/Makefile.am1
-rw-r--r--src/FbTk/MemFun.hh139
-rw-r--r--src/FbTk/Signal.hh218
-rw-r--r--src/FbTk/Slot.hh294
-rw-r--r--src/tests/Makefile6
-rw-r--r--src/tests/testSignals.cc121
7 files changed, 783 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 94da1ba..da15ff6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,9 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.1.2:
3*08/09/18:
4 * Added new Signal/Slot system to FbTk (Henrik)
5 This is suppose to replace the obsolete Subject/Observer classes.
6 FbTk/Signal.hh, FbTk/Slot.hh, FbTk/MemFun.hh, tests/testSignals.cc
2Changes for 1.1.1 7Changes for 1.1.1
3*08/09/14: 8*08/09/14:
4 * Fixed a minor pixmap resource leak (Henrik) 9 * Fixed a minor pixmap resource leak (Henrik)
diff --git a/src/FbTk/Makefile.am b/src/FbTk/Makefile.am
index 0033ab9..2d2f3a2 100644
--- a/src/FbTk/Makefile.am
+++ b/src/FbTk/Makefile.am
@@ -63,6 +63,7 @@ libFbTk_a_SOURCES = App.hh App.cc Color.cc Color.hh Command.hh \
63 TypeAhead.hh SearchResult.hh SearchResult.cc ITypeAheadable.hh \ 63 TypeAhead.hh SearchResult.hh SearchResult.cc ITypeAheadable.hh \
64 Select2nd.hh STLUtil.hh \ 64 Select2nd.hh STLUtil.hh \
65 CachedPixmap.hh CachedPixmap.cc \ 65 CachedPixmap.hh CachedPixmap.cc \
66 Slot.hh Signal.hh MemFun.hh \
66 ${xpm_SOURCE} \ 67 ${xpm_SOURCE} \
67 ${xft_SOURCE} \ 68 ${xft_SOURCE} \
68 ${xmb_SOURCE} \ 69 ${xmb_SOURCE} \
diff --git a/src/FbTk/MemFun.hh b/src/FbTk/MemFun.hh
new file mode 100644
index 0000000..4c834dd
--- /dev/null
+++ b/src/FbTk/MemFun.hh
@@ -0,0 +1,139 @@
1// MemFun.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_MEM_FUN_HH
23#define FBTK_MEM_FUN_HH
24
25namespace FbTk {
26
27/// No argument functor
28template <typename ReturnType, typename Object>
29class MemFun0 {
30public:
31 typedef ReturnType (Object:: *Action)();
32
33 MemFun0(Object& obj, Action action):
34 m_obj(obj),
35 m_action(action) {
36 }
37
38 void operator ()() {
39 (m_obj.*m_action)();
40 }
41
42private:
43 Object& m_obj;
44 Action m_action;
45};
46
47
48template <typename ReturnType, typename Object>
49MemFun0<ReturnType, Object>
50MemFun( Object& obj, ReturnType (Object:: *action)() ) {
51 return MemFun0<ReturnType, Object>(obj, action);
52}
53
54/// One argument functor
55template <typename ReturnType, typename Object, typename Arg1>
56class MemFun1 {
57public:
58 typedef ReturnType (Object:: *Action)(Arg1);
59
60 MemFun1(Object& obj, Action action):
61 m_obj(obj),
62 m_action(action) {
63 }
64
65 void operator ()(Arg1 arg1) {
66 (m_obj.*m_action)(arg1);
67 }
68
69private:
70 Object& m_obj;
71 Action m_action;
72};
73
74/// One argument functor helper function
75template <typename ReturnType, typename Object, typename Arg1>
76MemFun1<ReturnType, Object, Arg1>
77MemFun( Object& obj, ReturnType (Object:: *action)(Arg1) ) {
78 return MemFun1<ReturnType, Object, Arg1>(obj, action);
79}
80
81/// Two argument functor
82template <typename ReturnType, typename Object, typename Arg1, typename Arg2>
83class MemFun2 {
84public:
85 typedef ReturnType (Object:: *Action)(Arg1,Arg2);
86
87 MemFun2(Object& obj, Action action):
88 m_obj(obj),
89 m_action(action) {
90 }
91
92 void operator ()(Arg1 arg1, Arg2 arg2) {
93 (m_obj.*m_action)(arg1, arg2);
94 }
95
96private:
97 Object& m_obj;
98 Action m_action;
99};
100
101/// Two argument functor helper function
102template <typename ReturnType, typename Object, typename Arg1, typename Arg2>
103MemFun2<ReturnType, Object, Arg1, Arg2>
104MemFun( Object& obj, ReturnType (Object:: *action)(Arg1,Arg2) ) {
105 return MemFun2<ReturnType, Object, Arg1, Arg2>(obj, action);
106}
107
108/// Three argument functor
109template <typename ReturnType, typename Object,
110 typename Arg1, typename Arg2, typename Arg3>
111class MemFun3 {
112public:
113 typedef ReturnType (Object:: *Action)(Arg1,Arg2,Arg3);
114
115 MemFun3(Object& obj, Action action):
116 m_obj(obj),
117 m_action(action) {
118 }
119
120 void operator ()(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
121 (m_obj.*m_action)(arg1, arg2, arg3);
122 }
123
124private:
125 Object& m_obj;
126 Action m_action;
127};
128
129/// Three argument functor helper
130template <typename ReturnType, typename Object, typename Arg1, typename Arg2, typename Arg3>
131MemFun3<ReturnType, Object, Arg1, Arg2, Arg3>
132MemFun( Object& obj, ReturnType (Object:: *action)(Arg1, Arg2, Arg3) ) {
133 return MemFun3<ReturnType, Object, Arg1, Arg2, Arg3>(obj, action);
134}
135
136} // namespace FbTk
137
138#endif // FBTK_MEM_FUN_HH
139
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
diff --git a/src/FbTk/Slot.hh b/src/FbTk/Slot.hh
new file mode 100644
index 0000000..ba3cfc4
--- /dev/null
+++ b/src/FbTk/Slot.hh
@@ -0,0 +1,294 @@
1// Slot.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_SLOT_HH
23#define FBTK_SLOT_HH
24
25namespace FbTk {
26
27/// \namespace Implementation details for signals, do not use anything in this namespace
28namespace SigImpl {
29
30class CallbackHolder;
31
32/// Placeholder type for typed callbacks
33typedef void* (*CallbackFunc)(void *);
34/// Clone function callback type for cloning typed callback holders
35typedef CallbackHolder* (*CloneFunc)(CallbackHolder*);
36/// Kill function callback type for destroying type specific information in
37/// FunctorHolder
38typedef void (*KillFunc)(CallbackHolder*);
39
40/// Holds clone, functor callback, and the kill function for FunctorHolder.
41class CallbackHolder {
42public:
43 /**
44 * @param callback The callback to call when a slot receives a signal.
45 * @param clone The callback to use for cloning a type specific instance of
46 * this classinstance.
47 * @param kill The callback that knows how to free the memory in type
48 * specific instance of this class.
49 */
50 CallbackHolder(CallbackFunc callback,
51 CloneFunc clone,
52 KillFunc kill):
53 m_callback(callback),
54 m_kill(kill),
55 m_clone(clone) { }
56
57 ~CallbackHolder() {
58 (*m_kill)(this);
59 }
60
61 /// @return a clone of this instance
62 CallbackHolder* clone() {
63 return (*m_clone)(this);
64 }
65
66 /// \c Callback to \c Functor specific callback
67 CallbackFunc m_callback;
68
69protected:
70
71 CallbackHolder& operator = (const CallbackHolder& other) {
72 if ( this == &other ) {
73 return *this;
74 }
75 m_callback = other.m_callback;
76 m_clone = other.m_clone;
77 m_kill = other.m_kill;
78
79 return *this;
80 }
81
82 CallbackHolder(const CallbackHolder& other) {
83 *this = other;
84 }
85
86private:
87 /// This function is called to kill this instance
88 KillFunc m_kill;
89 /// Functions that knows how to clone a specific \c Functor type
90 CloneFunc m_clone;
91};
92
93
94/// Holds the functor and creates a clone callback for \c Functor specific type
95template <typename Functor>
96class FunctorHolder: public CallbackHolder {
97public:
98 /// This type.
99 typedef FunctorHolder<Functor> Self;
100 /**
101 * @param functor The functor to be used when a signal is emitted.
102 * @param callback The callback to call when a signal is emitted.
103 */
104 FunctorHolder(const Functor& functor, CallbackFunc callback):
105 CallbackHolder(callback, &clone, &kill),
106 m_functor(functor) {
107 }
108
109 /// Specific clone for this Functor type
110 static CallbackHolder* clone(CallbackHolder* self) {
111 return new Self( static_cast<Self&>(*self));
112 }
113
114 static void kill(CallbackHolder* self) {
115 // Destroy functor
116 static_cast<Self*>( self )->m_functor.~Functor();
117 }
118
119 Functor m_functor; ///< the functor to use when a signal is emitted.
120};
121
122
123
124/// Callback with no arguments.
125template <typename Functor, typename ReturnType >
126struct Callback0 {
127 static ReturnType callback(CallbackHolder* base) {
128 static_cast< FunctorHolder<Functor>* >( base )->m_functor();
129 return ReturnType();
130 }
131
132 static CallbackFunc functionAddress() {
133 return reinterpret_cast<CallbackFunc>(&callback);
134 }
135};
136
137/// Callback with one argument
138template <typename Functor, typename ReturnType, typename Arg1>
139struct Callback1 {
140 typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1);
141
142 static ReturnType callback(CallbackHolder* base, Arg1 arg1) {
143 static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1);
144 return ReturnType();
145 }
146
147 static CallbackFunc functionAddress() {
148 return reinterpret_cast<CallbackFunc>(&callback);
149 }
150};
151
152/// Callback with two arguments
153template <typename Functor, typename ReturnType,
154 typename Arg1, typename Arg2>
155struct Callback2 {
156 typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2);
157
158 static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2) {
159 static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1, arg2);
160 return ReturnType();
161 }
162
163 static CallbackFunc functionAddress() {
164 return reinterpret_cast<CallbackFunc>(&callback);
165 }
166};
167
168/// Callback with three arguments
169template <typename Functor, typename ReturnType,
170 typename Arg1, typename Arg2, typename Arg3>
171struct Callback3 {
172 typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3);
173
174 static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2, Arg3 arg3) {
175 static_cast< FunctorHolder<Functor>* >( base )->m_functor( arg1, arg2, arg3 );
176 return ReturnType();
177 }
178
179 static CallbackFunc functionAddress() {
180 return reinterpret_cast<CallbackFunc>(&callback);
181 }
182};
183
184/// Holds callback holder and handles the copying of callback holders for the
185/// \c Slots.
186class SlotHolder {
187public:
188 SlotHolder(const SlotHolder& other):
189 m_holder( other.m_holder ? other.m_holder->clone() : 0 ) {
190 }
191
192 ~SlotHolder() {
193 delete m_holder;
194 }
195
196 SlotHolder& operator = (const SlotHolder& other) {
197 if ( &other == this ) {
198 return *this;
199 }
200 delete m_holder;
201 if ( other.m_holder ) {
202 m_holder = other.m_holder->clone();
203 } else {
204 m_holder = 0;
205 }
206 return *this;
207 }
208
209 SlotHolder():m_holder( 0 ) { }
210
211protected:
212 explicit SlotHolder(CallbackHolder* holder):
213 m_holder( holder ) {
214 }
215
216 CallbackHolder* m_holder;
217};
218
219/// Slot with no argument.
220template <typename ReturnType>
221class Slot0: public SlotHolder {
222public:
223 typedef ReturnType (*CallbackType)(CallbackHolder*);
224
225 template <typename Functor>
226 Slot0( const Functor& functor ):
227 SlotHolder( new FunctorHolder<Functor>
228 (functor, Callback0<Functor, ReturnType>::functionAddress())) {
229 }
230
231 void operator()() {
232 reinterpret_cast<CallbackType>(m_holder->m_callback)( m_holder );
233 }
234};
235
236/// Slot with one argument.
237template <typename ReturnType, typename Arg1>
238class Slot1:public SlotHolder {
239public:
240 typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1);
241
242 template <typename Functor>
243 Slot1( const Functor& functor ):
244 SlotHolder( new FunctorHolder<Functor>
245 (functor, Callback1<Functor, ReturnType, Arg1>::functionAddress())){
246
247 }
248
249 void operator()(Arg1 arg) {
250 reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg);
251 }
252
253};
254
255/// Slot with two arguments
256template <typename ReturnType, typename Arg1, typename Arg2>
257class Slot2: public SlotHolder {
258public:
259 typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2);
260 template <typename Functor>
261 Slot2( const Functor& functor ):
262 SlotHolder( new FunctorHolder<Functor>
263 (functor, Callback2<Functor, ReturnType, Arg1, Arg2>::functionAddress())){
264
265 }
266
267 void operator()(Arg1 arg1, Arg2 arg2) {
268 reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg1, arg2);
269 }
270};
271
272/// Slot with three arguments
273template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
274class Slot3: public SlotHolder {
275public:
276 typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3);
277 template <typename Functor>
278 Slot3( const Functor& functor ):
279 SlotHolder( new FunctorHolder<Functor>
280 (functor, Callback3<Functor, ReturnType, Arg1, Arg2, Arg3>::functionAddress())){
281
282 }
283
284 void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
285 reinterpret_cast<CallbackType>(m_holder->m_callback)
286 ( m_holder, arg1, arg2, arg3 );
287 }
288};
289
290} // namespace SigImpl
291
292} // namespace FbTk
293
294#endif // FBTK_SLOT_H
diff --git a/src/tests/Makefile b/src/tests/Makefile
index 8d1c482..668126e 100644
--- a/src/tests/Makefile
+++ b/src/tests/Makefile
@@ -7,7 +7,8 @@ COMPILEFILE=$(CXX) -c $(CXXFLAGS)
7FONT_OBJ = ../FbTk/libFbTk.a 7FONT_OBJ = ../FbTk/libFbTk.a
8COMPILE = ${CXX} ${CXXFLAGS} ${XLIBS} 8COMPILE = ${CXX} ${CXXFLAGS} ${XLIBS}
9 9
10all: testMenu testFont testTexture movetest 10all: testMenu testFont testTexture movetest testSignals
11
11 12
12.cc.o: 13.cc.o:
13 $(CXX) -c $(CXXFLAGS) $< 14 $(CXX) -c $(CXXFLAGS) $<
@@ -15,6 +16,9 @@ all: testMenu testFont testTexture movetest
15glxtest: ../FbTk/App.hh glxtest.cc 16glxtest: ../FbTk/App.hh glxtest.cc
16 ${CXX} glxtest.cc ${CXXFLAGS} ${XLIBS} -lGL -lGLU -lXpm -o glxtest 17 ${CXX} glxtest.cc ${CXXFLAGS} ${XLIBS} -lGL -lGLU -lXpm -o glxtest
17 18
19testSignals: testSignals.o ../FbTk/Signal.hh ../FbTk/MemFun.hh
20 $(CXX) $(LIBS) testSignals.o -o testSignals
21
18testStringUtil: StringUtiltest.o 22testStringUtil: StringUtiltest.o
19 $(CXX) $(LIBS) StringUtiltest.o ../FbTk/libFbTk.a -o testStringUtil 23 $(CXX) $(LIBS) StringUtiltest.o ../FbTk/libFbTk.a -o testStringUtil
20 24
diff --git a/src/tests/testSignals.cc b/src/tests/testSignals.cc
new file mode 100644
index 0000000..86096bf
--- /dev/null
+++ b/src/tests/testSignals.cc
@@ -0,0 +1,121 @@
1#include <iostream>
2using namespace std;
3
4#include "../FbTk/Signal.hh"
5#include "../FbTk/MemFun.hh"
6
7#include <string>
8
9
10
11struct NoArgument {
12 void operator() () const {
13 cout << "No Argument." << endl;
14 }
15};
16
17struct OneArgument {
18 void operator ()( int value ) {
19 cout << "One argument = " << value << endl;
20 }
21};
22
23struct TwoArguments {
24 void operator ()( int value, const string& message ) {
25 cout << "Two arguments, (1) = " << value << ", (2) = " << message << endl;
26 }
27};
28
29struct ThreeArguments {
30 void operator ()( int value, const string& message, double value2 ) {
31 cout << "Two arguments, (1) = " << value << ", (2) = " << message
32 << ", (3) = " << value2 << endl;
33 }
34};
35
36struct FunctionClass {
37 FunctionClass() {
38 cout << "FunctionClass created." << endl;
39 }
40 ~FunctionClass() {
41 cout << "FunctionClass deleted." << endl;
42 }
43 void print() {
44 cout << "Printing." << endl;
45 }
46
47 void takeIt( string& str ) {
48 cout << "takeIt( " << str << ")" << endl;
49 }
50
51 void showMessage( int value, const string& message ) {
52 cout << "(" << value << "): " << message << endl;
53 }
54 void threeArgs( int value, const string& str, double pi ) {
55 cout << "(" << value << "): " << str << ", pi = " << pi << endl;
56 }
57};
58
59int main() {
60 using FbTk::Signal;
61 using FbTk::SignalTracker;
62
63 Signal<void> no_arg;
64 no_arg.connect( NoArgument() );
65
66 Signal<void, int> one_arg;
67 one_arg.connect( OneArgument() );
68
69 Signal<void, int, const string&> two_args;
70 two_args.connect( TwoArguments() );
71
72 Signal<void, int, const string&, double> three_args;
73 three_args.connect( ThreeArguments() );
74
75 // emit test
76 no_arg.emit();
77 one_arg.emit( 10 );
78 two_args.emit( 10, "Message" );
79 three_args.emit( 10, "Three", 3.141592 );
80
81 // test signal tracker
82 {
83 cout << "---- tracker ----" << endl;
84 SignalTracker tracker;
85 // setup two new slots and track them
86 SignalTracker::TrackID id_no_arg = tracker.join( no_arg, NoArgument() );
87 SignalTracker::TrackID id_one_arg = tracker.join( one_arg, OneArgument() );
88
89 // two outputs each from these two signals
90 no_arg.emit();
91 one_arg.emit( 31 );
92
93 // stop tracking id_one_arg, which should keep the slot after this scope,
94 // the id_no_arg connection should be destroyed after this.
95 tracker.leave( id_one_arg );
96 cout << "---- tracker end ----" << endl;
97 }
98
99 // now we should have one output from no_arg and two outputs from one_arg
100 no_arg.emit();
101 one_arg.emit( 2 );
102
103 using FbTk::MemFun;
104 FunctionClass obj;
105 no_arg.clear();
106 no_arg.connect(MemFun(obj, &FunctionClass::print));
107 no_arg.emit();
108
109 string takeThis("Take this");
110 Signal<void, string&> ref_arg;
111 ref_arg.connect(MemFun(obj, &FunctionClass::takeIt));
112 ref_arg.emit( takeThis );
113
114 two_args.clear();
115 two_args.connect(MemFun(obj, &FunctionClass::showMessage));
116 two_args.emit(10, "This is a message");
117
118 three_args.clear();
119 three_args.connect(MemFun(obj, &FunctionClass::threeArgs));
120 three_args.emit(9, "nine", 3.141592);
121}