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 76 explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) : 77 maUpdaters(), 78 maViewUpdateRequests(), 79 mrViewContainer(rViewContainer), 80 mbUpdateAllRequest(false), 81 mbViewClobbered(false), 82 mnLockCount(0) 83 {} 84 }; 85 86 ScreenUpdater::ScreenUpdater( UnoViewContainer const& rViewContainer ) : 87 mpImpl(new ImplScreenUpdater(rViewContainer) ) 88 { 89 } 90 91 ScreenUpdater::~ScreenUpdater() 92 { 93 // outline because of pimpl 94 } 95 96 void ScreenUpdater::notifyUpdate() 97 { 98 mpImpl->mbUpdateAllRequest = true; 99 } 100 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 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 182 void ScreenUpdater::addViewUpdate( ViewUpdateSharedPtr const& rViewUpdate ) 183 { 184 mpImpl->maUpdaters.add( rViewUpdate ); 185 } 186 187 void ScreenUpdater::removeViewUpdate( ViewUpdateSharedPtr const& rViewUpdate ) 188 { 189 mpImpl->maUpdaters.remove( rViewUpdate ); 190 } 191 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 205 void ScreenUpdater::lockUpdates (void) 206 { 207 ++mpImpl->mnLockCount; 208 OSL_ASSERT(mpImpl->mnLockCount>0); 209 } 210 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 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 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 246 UpdateLock::~UpdateLock (void) 247 { 248 if (mbIsActivated) 249 mrUpdater.unlockUpdates(); 250 } 251 252 253 254 255 void UpdateLock::Activate (void) 256 { 257 if ( ! mbIsActivated) 258 { 259 mbIsActivated = true; 260 mrUpdater.lockUpdates(); 261 } 262 } 263 264 } 265