aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Labath <pavelo@centrum.sk>2011-05-02 21:01:24 (GMT)
committerPavel Labath <pavelo@centrum.sk>2011-05-10 11:00:45 (GMT)
commitbef2039d2c5a31ab9f974059d991557276647af1 (patch)
tree88feb5d8d2f7ac1915325d5506aea71e07386d9f
parent144d716a42072bd59f6c99e95e86be4486285782 (diff)
downloadfluxbox_pavel-bef2039d2c5a31ab9f974059d991557276647af1.zip
fluxbox_pavel-bef2039d2c5a31ab9f974059d991557276647af1.tar.bz2
Don't crash when a slot is deregistered in the middle of signal processing
this was possible (and used) with FbTk::Subject, but the implemetation of FbTk::Signal didn't support it, which made it impossible to continue with conversion.
-rw-r--r--src/FbTk/Signal.hh61
1 files changed, 46 insertions, 15 deletions
diff --git a/src/FbTk/Signal.hh b/src/FbTk/Signal.hh
index 71a4d6e..432bb3f 100644
--- a/src/FbTk/Signal.hh
+++ b/src/FbTk/Signal.hh
@@ -24,9 +24,9 @@
24 24
25#include "RefCount.hh" 25#include "RefCount.hh"
26#include "Slot.hh" 26#include "Slot.hh"
27#include <algorithm>
27#include <list> 28#include <list>
28#include <map> 29#include <map>
29#include <vector>
30#include <set> 30#include <set>
31 31
32namespace FbTk { 32namespace FbTk {
@@ -40,6 +40,10 @@ namespace SigImpl {
40 * handled by the child class so it can do the type checking. 40 * handled by the child class so it can do the type checking.
41 */ 41 */
42class SignalHolder { 42class SignalHolder {
43protected:
44 typedef RefCount<SlotBase> SlotPtr;
45 typedef std::list<SlotPtr> SlotList;
46
43public: 47public:
44 /// Special tracker interface used by SignalTracker. 48 /// Special tracker interface used by SignalTracker.
45 class Tracker { 49 class Tracker {
@@ -49,13 +53,12 @@ public:
49 virtual void disconnect(SignalHolder& signal) = 0; 53 virtual void disconnect(SignalHolder& signal) = 0;
50 }; 54 };
51 55
52 /// Do not use this type outside this class
53 typedef std::list<RefCount<SlotBase> > SlotList;
54
55 typedef SlotList::iterator Iterator; 56 typedef SlotList::iterator Iterator;
56 typedef Iterator SlotID; 57 typedef Iterator SlotID;
57 typedef SlotList::const_iterator ConstIterator; 58 typedef SlotList::const_iterator ConstIterator;
58 59
60 SignalHolder() : m_emitting(0) {}
61
59 ~SignalHolder() { 62 ~SignalHolder() {
60 // Disconnect this holder from all trackers. 63 // Disconnect this holder from all trackers.
61 for (Trackers::iterator it = m_trackers.begin(), 64 for (Trackers::iterator it = m_trackers.begin(),
@@ -67,13 +70,21 @@ public:
67 70
68 /// Remove a specific slot \c id from this signal 71 /// Remove a specific slot \c id from this signal
69 void disconnect(SlotID slotIt) { 72 void disconnect(SlotID slotIt) {
70 m_slots.erase( slotIt ); 73 if(m_emitting) {
74 // if we are emitting, we must not erase the actual element, as that would
75 // invalidate iterators in the emit() function
76 *slotIt = SlotPtr();
77 } else
78 m_slots.erase( slotIt );
71 } 79 }
72 80
73 81
74 /// Removes all slots connected to this 82 /// Removes all slots connected to this
75 void clear() { 83 void clear() {
76 m_slots.clear(); 84 if(m_emitting)
85 std::fill(m_slots.begin(), m_slots.end(), SlotPtr());
86 else
87 m_slots.clear();
77 } 88 }
78 89
79 void connectTracker(SignalHolder::Tracker& tracker) { 90 void connectTracker(SignalHolder::Tracker& tracker) {
@@ -92,14 +103,22 @@ protected:
92 Iterator end() { return m_slots.end(); } 103 Iterator end() { return m_slots.end(); }
93 104
94 /// Connect a slot to this signal. Must only be called by child classes. 105 /// Connect a slot to this signal. Must only be called by child classes.
95 SlotID connect(const RefCount<SlotBase>& slot) { 106 SlotID connect(const SlotPtr& slot) {
96 return m_slots.insert(m_slots.end(), slot); 107 return m_slots.insert(m_slots.end(), slot);
97 } 108 }
98 109
110 void begin_emitting() { ++m_emitting; }
111 void end_emitting() {
112 if(--m_emitting == 0) {
113 // remove elements which belonged slots that detached themselves
114 m_slots.erase(std::remove(m_slots.begin(), m_slots.end(), SlotPtr()), m_slots.end());
115 }
116 }
99private: 117private:
100 typedef std::set<Tracker*> Trackers; 118 typedef std::set<Tracker*> Trackers;
101 SlotList m_slots; ///< all slots connected to a signal 119 SlotList m_slots; ///< all slots connected to a signal
102 Trackers m_trackers; ///< all instances that tracks this signal. 120 Trackers m_trackers; ///< all instances that tracks this signal.
121 unsigned m_emitting;
103}; 122};
104 123
105struct EmptyArg {}; 124struct EmptyArg {};
@@ -113,14 +132,17 @@ template <typename ReturnType,
113class Signal: public SigImpl::SignalHolder { 132class Signal: public SigImpl::SignalHolder {
114public: 133public:
115 void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) { 134 void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
135 begin_emitting();
116 for ( Iterator it = begin(); it != end(); ++it ) { 136 for ( Iterator it = begin(); it != end(); ++it ) {
117 static_cast<SigImpl::SlotBase3<ReturnType, Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3); 137 if(*it)
138 static_cast<SigImpl::SlotBase3<ReturnType, Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3);
118 } 139 }
140 end_emitting();
119 } 141 }
120 142
121 template<typename Functor> 143 template<typename Functor>
122 SlotID connect(const Functor& functor) { 144 SlotID connect(const Functor& functor) {
123 return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>( 145 return SignalHolder::connect(SlotPtr(
124 new SigImpl::Slot3<ReturnType, Arg1, Arg2, Arg3, Functor>(functor) 146 new SigImpl::Slot3<ReturnType, Arg1, Arg2, Arg3, Functor>(functor)
125 )); 147 ));
126 } 148 }
@@ -131,14 +153,17 @@ template <typename ReturnType, typename Arg1, typename Arg2>
131class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder { 153class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
132public: 154public:
133 void emit(Arg1 arg1, Arg2 arg2) { 155 void emit(Arg1 arg1, Arg2 arg2) {
156 begin_emitting();
134 for ( Iterator it = begin(); it != end(); ++it ) { 157 for ( Iterator it = begin(); it != end(); ++it ) {
135 static_cast<SigImpl::SlotBase2<ReturnType, Arg1, Arg2> &>(**it)(arg1, arg2); 158 if(*it)
159 static_cast<SigImpl::SlotBase2<ReturnType, Arg1, Arg2> &>(**it)(arg1, arg2);
136 } 160 }
161 end_emitting();
137 } 162 }
138 163
139 template<typename Functor> 164 template<typename Functor>
140 SlotID connect(const Functor& functor) { 165 SlotID connect(const Functor& functor) {
141 return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>( 166 return SignalHolder::connect(SlotPtr(
142 new SigImpl::Slot2<ReturnType, Arg1, Arg2, Functor>(functor) 167 new SigImpl::Slot2<ReturnType, Arg1, Arg2, Functor>(functor)
143 )); 168 ));
144 } 169 }
@@ -149,14 +174,17 @@ template <typename ReturnType, typename Arg1>
149class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { 174class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
150public: 175public:
151 void emit(Arg1 arg) { 176 void emit(Arg1 arg) {
177 begin_emitting();
152 for ( Iterator it = begin(); it != end(); ++it ) { 178 for ( Iterator it = begin(); it != end(); ++it ) {
153 static_cast<SigImpl::SlotBase1<ReturnType, Arg1> &>(**it)(arg); 179 if(*it)
180 static_cast<SigImpl::SlotBase1<ReturnType, Arg1> &>(**it)(arg);
154 } 181 }
182 end_emitting();
155 } 183 }
156 184
157 template<typename Functor> 185 template<typename Functor>
158 SlotID connect(const Functor& functor) { 186 SlotID connect(const Functor& functor) {
159 return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>( 187 return SignalHolder::connect(SlotPtr(
160 new SigImpl::Slot1<ReturnType, Arg1, Functor>(functor) 188 new SigImpl::Slot1<ReturnType, Arg1, Functor>(functor)
161 )); 189 ));
162 } 190 }
@@ -167,14 +195,17 @@ template <typename ReturnType>
167class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { 195class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
168public: 196public:
169 void emit() { 197 void emit() {
198 begin_emitting();
170 for ( Iterator it = begin(); it != end(); ++it ) { 199 for ( Iterator it = begin(); it != end(); ++it ) {
171 static_cast<SigImpl::SlotBase0<ReturnType> &>(**it)(); 200 if(*it)
201 static_cast<SigImpl::SlotBase0<ReturnType> &>(**it)();
172 } 202 }
203 end_emitting();
173 } 204 }
174 205
175 template<typename Functor> 206 template<typename Functor>
176 SlotID connect(const Functor& functor) { 207 SlotID connect(const Functor& functor) {
177 return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>( 208 return SignalHolder::connect(SlotPtr(
178 new SigImpl::Slot0<ReturnType, Functor>(functor) 209 new SigImpl::Slot0<ReturnType, Functor>(functor)
179 )); 210 ));
180 } 211 }