1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 #include "precompiled_slideshow.hxx"
23
24 #include "screenupdater.hxx"
25 #include "listenercontainer.hxx"
26
27 #include <boost/bind.hpp>
28 #include <vector>
29 #include <algorithm>
30
31 namespace {
32 class UpdateLock : public ::slideshow::internal::ScreenUpdater::UpdateLock
33 {
34 public:
35 UpdateLock (::slideshow::internal::ScreenUpdater& rUpdater, const bool bStartLocked);
36 virtual ~UpdateLock (void);
37 virtual void Activate (void);
38 private:
39 ::slideshow::internal::ScreenUpdater& mrUpdater;
40 bool mbIsActivated;
41 };
42 }
43
44 namespace slideshow
45 {
46 namespace internal
47 {
48 typedef std::vector<
49 std::pair<UnoViewSharedPtr,bool> > UpdateRequestVector;
50
51 struct ScreenUpdater::ImplScreenUpdater
52 {
53 /** List of registered ViewUpdaters, to consult for necessary
54 updates
55 */
56 ThreadUnsafeListenerContainer<
57 ViewUpdateSharedPtr,
58 std::vector<ViewUpdateSharedPtr> > maUpdaters;
59
60 // Views that have been notified for update
61 UpdateRequestVector maViewUpdateRequests;
62
63 // List of View. Used to issue screen updates on.
64 UnoViewContainer const& mrViewContainer;
65
66 // True, if a notifyUpdate() for all views has been issued.
67 bool mbUpdateAllRequest;
68
69 // True, if at least one notifyUpdate() call had bViewClobbered set
70 bool mbViewClobbered;
71
72 // The screen is updated only when mnLockCount==0
73 sal_Int32 mnLockCount;
74
ImplScreenUpdaterslideshow::internal::ScreenUpdater::ImplScreenUpdater75 explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) :
76 maUpdaters(),
77 maViewUpdateRequests(),
78 mrViewContainer(rViewContainer),
79 mbUpdateAllRequest(false),
80 mbViewClobbered(false),
81 mnLockCount(0)
82 {}
83 };
84
ScreenUpdater(UnoViewContainer const & rViewContainer)85 ScreenUpdater::ScreenUpdater( UnoViewContainer const& rViewContainer ) :
86 mpImpl(new ImplScreenUpdater(rViewContainer) )
87 {
88 }
89
~ScreenUpdater()90 ScreenUpdater::~ScreenUpdater()
91 {
92 // outline because of pimpl
93 }
94
notifyUpdate()95 void ScreenUpdater::notifyUpdate()
96 {
97 mpImpl->mbUpdateAllRequest = true;
98 }
99
notifyUpdate(const UnoViewSharedPtr & rView,bool bViewClobbered)100 void ScreenUpdater::notifyUpdate( const UnoViewSharedPtr& rView,
101 bool bViewClobbered )
102 {
103 mpImpl->maViewUpdateRequests.push_back(
104 std::make_pair(rView, bViewClobbered) );
105
106 if( bViewClobbered )
107 mpImpl->mbViewClobbered = true;
108 }
109
commitUpdates()110 void ScreenUpdater::commitUpdates()
111 {
112 if (mpImpl->mnLockCount > 0)
113 return;
114
115 // cases:
116 //
117 // (a) no update necessary at all
118 //
119 // (b) no ViewUpdate-generated update
120 // I. update all views requested -> for_each( mrViewContainer )
121 // II. update some views requested -> for_each( maViewUpdateRequests )
122 //
123 // (c) ViewUpdate-triggered update - update all views
124 //
125
126 // any ViewUpdate-triggered updates?
127 const bool bViewUpdatesNeeded(
128 mpImpl->maUpdaters.apply(
129 boost::mem_fn(&ViewUpdate::needsUpdate)) );
130
131 if( bViewUpdatesNeeded )
132 {
133 mpImpl->maUpdaters.applyAll(
134 boost::mem_fn((bool (ViewUpdate::*)())&ViewUpdate::update) );
135 }
136
137 if( bViewUpdatesNeeded ||
138 mpImpl->mbUpdateAllRequest )
139 {
140 // unconditionally update all views
141 std::for_each( mpImpl->mrViewContainer.begin(),
142 mpImpl->mrViewContainer.end(),
143 mpImpl->mbViewClobbered ?
144 boost::mem_fn(&View::paintScreen) :
145 boost::mem_fn(&View::updateScreen) );
146 }
147 else if( !mpImpl->maViewUpdateRequests.empty() )
148 {
149 // update notified views only
150 UpdateRequestVector::const_iterator aIter(
151 mpImpl->maViewUpdateRequests.begin() );
152 const UpdateRequestVector::const_iterator aEnd(
153 mpImpl->maViewUpdateRequests.end() );
154 while( aIter != aEnd )
155 {
156 // TODO(P1): this is O(n^2) in the number of views, if
157 // lots of views notify updates.
158 const UnoViewVector::const_iterator aEndOfViews(
159 mpImpl->mrViewContainer.end() );
160 UnoViewVector::const_iterator aFoundView;
161 if( (aFoundView=std::find(mpImpl->mrViewContainer.begin(),
162 aEndOfViews,
163 aIter->first)) != aEndOfViews )
164 {
165 if( aIter->second )
166 (*aFoundView)->paintScreen(); // force-paint
167 else
168 (*aFoundView)->updateScreen(); // update changes only
169 }
170
171 ++aIter;
172 }
173 }
174
175 // done - clear requests
176 mpImpl->mbViewClobbered = false;
177 mpImpl->mbUpdateAllRequest = false;
178 UpdateRequestVector().swap( mpImpl->maViewUpdateRequests );
179 }
180
addViewUpdate(ViewUpdateSharedPtr const & rViewUpdate)181 void ScreenUpdater::addViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
182 {
183 mpImpl->maUpdaters.add( rViewUpdate );
184 }
185
removeViewUpdate(ViewUpdateSharedPtr const & rViewUpdate)186 void ScreenUpdater::removeViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
187 {
188 mpImpl->maUpdaters.remove( rViewUpdate );
189 }
190
requestImmediateUpdate()191 void ScreenUpdater::requestImmediateUpdate()
192 {
193 if (mpImpl->mnLockCount > 0)
194 return;
195
196 // TODO(F2): This will interfere with other updates, since it
197 // happens out-of-sync with main animation loop. Might cause
198 // artifacts.
199 std::for_each( mpImpl->mrViewContainer.begin(),
200 mpImpl->mrViewContainer.end(),
201 boost::mem_fn(&View::updateScreen) );
202 }
203
lockUpdates(void)204 void ScreenUpdater::lockUpdates (void)
205 {
206 ++mpImpl->mnLockCount;
207 OSL_ASSERT(mpImpl->mnLockCount>0);
208 }
209
unlockUpdates(void)210 void ScreenUpdater::unlockUpdates (void)
211 {
212 OSL_ASSERT(mpImpl->mnLockCount>0);
213 if (mpImpl->mnLockCount > 0)
214 {
215 --mpImpl->mnLockCount;
216 if (mpImpl->mnLockCount)
217 commitUpdates();
218 }
219 }
220
createLock(const bool bStartLocked)221 ::boost::shared_ptr<ScreenUpdater::UpdateLock> ScreenUpdater::createLock (const bool bStartLocked)
222 {
223 return ::boost::shared_ptr<ScreenUpdater::UpdateLock>(new ::UpdateLock(*this, bStartLocked));
224 }
225
226
227 } // namespace internal
228 } // namespace slideshow
229
230 namespace {
231
UpdateLock(::slideshow::internal::ScreenUpdater & rUpdater,const bool bStartLocked)232 UpdateLock::UpdateLock (
233 ::slideshow::internal::ScreenUpdater& rUpdater,
234 const bool bStartLocked)
235 : mrUpdater(rUpdater),
236 mbIsActivated(false)
237 {
238 if (bStartLocked)
239 Activate();
240 }
241
242
~UpdateLock(void)243 UpdateLock::~UpdateLock (void)
244 {
245 if (mbIsActivated)
246 mrUpdater.unlockUpdates();
247 }
248
249
Activate(void)250 void UpdateLock::Activate (void)
251 {
252 if ( ! mbIsActivated)
253 {
254 mbIsActivated = true;
255 mrUpdater.lockUpdates();
256 }
257 }
258
259 }
260
261 /* vim: set noet sw=4 ts=4: */
262