1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <tools/diagnose_ex.h>
22 #include <osl/diagnose.h>
23 #include <sal/log.hxx>
24 
25 #include <slideshowexceptions.hxx>
26 #include <activity.hxx>
27 #include <activitiesqueue.hxx>
28 
29 #include <algorithm>
30 #include <memory>
31 
32 
33 using namespace ::com::sun::star;
34 
35 namespace slideshow::internal
36 {
ActivitiesQueue(const std::shared_ptr<::canvas::tools::ElapsedTime> & pPresTimer)37         ActivitiesQueue::ActivitiesQueue(
38           const std::shared_ptr< ::canvas::tools::ElapsedTime >& pPresTimer ) :
39             mpTimer( pPresTimer ),
40             maCurrentActivitiesWaiting(),
41             maCurrentActivitiesReinsert(),
42             maDequeuedActivities()
43         {
44         }
45 
~ActivitiesQueue()46         ActivitiesQueue::~ActivitiesQueue()
47         {
48             // dispose all queue entries
49             try
50             {
51                 for( const auto& pActivity : maCurrentActivitiesWaiting )
52                     pActivity->dispose();
53                 for( const auto& pActivity : maCurrentTailActivitiesWaiting )
54                     pActivity->dispose();
55                 for( const auto& pActivity : maCurrentActivitiesReinsert )
56                     pActivity->dispose();
57             }
58             catch (const uno::Exception&)
59             {
60                 TOOLS_WARN_EXCEPTION("slideshow", "");
61             }
62         }
63 
addActivity(const ActivitySharedPtr & pActivity)64         bool ActivitiesQueue::addActivity( const ActivitySharedPtr& pActivity )
65         {
66             OSL_ENSURE( pActivity, "ActivitiesQueue::addActivity: activity ptr NULL" );
67 
68             if( !pActivity )
69                 return false;
70 
71             // add entry to waiting list
72             maCurrentActivitiesWaiting.push_back( pActivity );
73 
74             return true;
75         }
76 
addTailActivity(const ActivitySharedPtr & pActivity)77         bool ActivitiesQueue::addTailActivity(const ActivitySharedPtr &pActivity)
78         {
79             OSL_ENSURE( pActivity, "ActivitiesQueue::addTailActivity: activity ptr NULL" );
80 
81             if( !pActivity )
82                 return false;
83 
84             // Activities that should be processed last are kept in a different
85             // ActivityQueue, and later appended to the end of the maCurrentActivitiesWaiting
86             // on the beginning of ActivitiesQueue::process()
87             maCurrentTailActivitiesWaiting.push_back( pActivity );
88 
89             return true;
90         }
91 
process()92         void ActivitiesQueue::process()
93         {
94             SAL_INFO("slideshow.verbose", "ActivitiesQueue: outer loop heartbeat" );
95 
96             // If there are activities to be processed last append them to the end of the ActivitiesQueue
97             maCurrentActivitiesWaiting.insert( maCurrentActivitiesWaiting.end(),
98                                                maCurrentTailActivitiesWaiting.begin(),
99                                                maCurrentTailActivitiesWaiting.end() );
100             maCurrentTailActivitiesWaiting.clear();
101 
102             // accumulate time lag for all activities, and lag time
103             // base if necessary:
104             double fLag = 0.0;
105             for ( const auto& rxActivity : maCurrentActivitiesWaiting )
106                 fLag = std::max<double>( fLag, rxActivity->calcTimeLag() );
107             if (fLag > 0.0)
108             {
109                 mpTimer->adjustTimer( -fLag );
110             }
111 
112             // process list of activities
113             while( !maCurrentActivitiesWaiting.empty() )
114             {
115                 // process topmost activity
116                 ActivitySharedPtr pActivity( maCurrentActivitiesWaiting.front() );
117                 maCurrentActivitiesWaiting.pop_front();
118 
119                 bool bReinsert( false );
120 
121                 try
122                 {
123                     // fire up activity
124                     bReinsert = pActivity->perform();
125                 }
126                 catch( uno::RuntimeException& )
127                 {
128                     throw;
129                 }
130                 catch( uno::Exception& )
131                 {
132                     // catch anything here, we don't want
133                     // to leave this scope under _any_
134                     // circumstance. Although, do _not_
135                     // reinsert an activity that threw
136                     // once.
137 
138                     // NOTE: we explicitly don't catch(...) here,
139                     // since this will also capture segmentation
140                     // violations and the like. In such a case, we
141                     // still better let our clients now...
142                     TOOLS_WARN_EXCEPTION( "slideshow", "" );
143                 }
144                 catch( SlideShowException& )
145                 {
146                     // catch anything here, we don't want
147                     // to leave this scope under _any_
148                     // circumstance. Although, do _not_
149                     // reinsert an activity that threw
150                     // once.
151 
152                     // NOTE: we explicitly don't catch(...) here,
153                     // since this will also capture segmentation
154                     // violations and the like. In such a case, we
155                     // still better let our clients now...
156                     SAL_WARN("slideshow", "::presentation::internal::ActivitiesQueue: Activity threw a SlideShowException, removing from ring" );
157                 }
158 
159                 if( bReinsert )
160                     maCurrentActivitiesReinsert.push_back( pActivity );
161                 else
162                     maDequeuedActivities.push_back( pActivity );
163 
164                 SAL_INFO("slideshow.verbose", "ActivitiesQueue: inner loop heartbeat" );
165             }
166 
167             if( !maCurrentActivitiesReinsert.empty() )
168             {
169                 // reinsert all processed, but not finished
170                 // activities back to waiting queue. With swap(),
171                 // we kill two birds with one stone: we reuse the
172                 // list nodes, and we clear the
173                 // maCurrentActivitiesReinsert list
174                 maCurrentActivitiesWaiting.swap( maCurrentActivitiesReinsert );
175             }
176         }
177 
processDequeued()178         void ActivitiesQueue::processDequeued()
179         {
180             // notify all dequeued activities from last round
181             for( const auto& pActivity : maDequeuedActivities )
182                 pActivity->dequeued();
183             maDequeuedActivities.clear();
184         }
185 
isEmpty() const186         bool ActivitiesQueue::isEmpty() const
187         {
188             return maCurrentActivitiesWaiting.empty() && maCurrentActivitiesReinsert.empty();
189         }
190 
clear()191         void ActivitiesQueue::clear()
192         {
193             // dequeue all entries:
194             for( const auto& pActivity : maCurrentActivitiesWaiting )
195                 pActivity->dequeued();
196             ActivityQueue().swap( maCurrentActivitiesWaiting );
197 
198             for( const auto& pActivity : maCurrentActivitiesReinsert )
199                 pActivity->dequeued();
200             ActivityQueue().swap( maCurrentActivitiesReinsert );
201         }
202 }
203 
204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
205