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