diff options
author | Henrik Kinnunen <fluxgen@fluxbox.org> | 2008-09-18 20:24:35 (GMT) |
---|---|---|
committer | Henrik Kinnunen <fluxgen@fluxbox.org> | 2008-09-18 20:24:35 (GMT) |
commit | e4d4717703b365bc14f189bf36b3edb1e4430b90 (patch) | |
tree | 1e678e6d0569714ab8c78fa0900c18ee1bb0f10a /src/FbTk/Signal.hh | |
parent | 8e97963e4211963f960c52c8a8f4bf5cd135ad2f (diff) | |
download | fluxbox-e4d4717703b365bc14f189bf36b3edb1e4430b90.zip fluxbox-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.
Diffstat (limited to 'src/FbTk/Signal.hh')
-rw-r--r-- | src/FbTk/Signal.hh | 218 |
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 | |||
29 | namespace FbTk { | ||
30 | |||
31 | /// \namespace Implementation details for signals, do not use anything in this namespace | ||
32 | namespace 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 | */ | ||
39 | class SignalHolder { | ||
40 | public: | ||
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 | |||
59 | protected: | ||
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 | |||
71 | private: | ||
72 | SlotList m_slots; ///< all slots connected to a signal | ||
73 | }; | ||
74 | |||
75 | /// Signal with no argument | ||
76 | template <typename ReturnType> | ||
77 | class Signal0: public SignalHolder { | ||
78 | public: | ||
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 | ||
94 | template <typename ReturnType, typename Arg1> | ||
95 | class Signal1: public SignalHolder { | ||
96 | public: | ||
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 | ||
112 | template <typename ReturnType, typename Arg1, typename Arg2> | ||
113 | class Signal2: public SignalHolder { | ||
114 | public: | ||
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 | ||
129 | template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3> | ||
130 | class Signal3: public SignalHolder { | ||
131 | public: | ||
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 | |||
146 | struct EmptyArg {}; | ||
147 | |||
148 | } // namespace SigImpl | ||
149 | |||
150 | |||
151 | /// Specialization for three arguments. | ||
152 | template <typename ReturnType, | ||
153 | typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg > | ||
154 | class Signal: public SigImpl::Signal3< ReturnType, Arg1, Arg2, Arg3 > { | ||
155 | public: | ||
156 | }; | ||
157 | |||
158 | /// Specialization for two arguments. | ||
159 | template <typename ReturnType, typename Arg1, typename Arg2> | ||
160 | class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::Signal2< ReturnType, Arg1, Arg2 > { | ||
161 | public: | ||
162 | }; | ||
163 | |||
164 | /// Specialization for one argument. | ||
165 | template <typename ReturnType, typename Arg1> | ||
166 | class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal1< ReturnType, Arg1 > { | ||
167 | public: | ||
168 | }; | ||
169 | |||
170 | /// Specialization for no argument. | ||
171 | template <typename ReturnType> | ||
172 | class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal0< ReturnType > { | ||
173 | public: | ||
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 | */ | ||
180 | class SignalTracker { | ||
181 | public: | ||
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 | |||
210 | private: | ||
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 | ||