xref: /trunk/main/slideshow/source/engine/screenupdater.cxx (revision ffd38472365e95f6a578737bc9a5eb0fac624a86)
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 
75         explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) :
76             maUpdaters(),
77             maViewUpdateRequests(),
78             mrViewContainer(rViewContainer),
79             mbUpdateAllRequest(false),
80             mbViewClobbered(false),
81             mnLockCount(0)
82         {}
83     };
84 
85     ScreenUpdater::ScreenUpdater( UnoViewContainer const& rViewContainer ) :
86         mpImpl(new ImplScreenUpdater(rViewContainer) )
87     {
88     }
89 
90     ScreenUpdater::~ScreenUpdater()
91     {
92         // outline because of pimpl
93     }
94 
95     void ScreenUpdater::notifyUpdate()
96     {
97         mpImpl->mbUpdateAllRequest = true;
98     }
99 
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 
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 
181     void ScreenUpdater::addViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
182     {
183         mpImpl->maUpdaters.add( rViewUpdate );
184     }
185 
186     void ScreenUpdater::removeViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
187     {
188         mpImpl->maUpdaters.remove( rViewUpdate );
189     }
190 
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 
204     void ScreenUpdater::lockUpdates (void)
205     {
206         ++mpImpl->mnLockCount;
207         OSL_ASSERT(mpImpl->mnLockCount>0);
208     }
209 
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 
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 
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 
243 UpdateLock::~UpdateLock (void)
244 {
245     if (mbIsActivated)
246         mrUpdater.unlockUpdates();
247 }
248 
249 
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