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