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