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 #include <services/desktop.hxx>
21 
22 #include <loadenv/loadenv.hxx>
23 #include <loadenv/targethelper.hxx>
24 
25 #include <helper/ocomponentaccess.hxx>
26 #include <helper/oframes.hxx>
27 #include <dispatch/dispatchprovider.hxx>
28 
29 #include <dispatch/interceptionhelper.hxx>
30 #include <classes/taskcreator.hxx>
31 #include <threadhelp/transactionguard.hxx>
32 #include <general.h>
33 #include <properties.h>
34 #include <targets.h>
35 
36 #include <strings.hrc>
37 #include <classes/fwkresid.hxx>
38 
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/frame/TerminationVetoException.hpp>
42 #include <com/sun/star/awt/XWindow.hpp>
43 #include <com/sun/star/awt/XWindowPeer.hpp>
44 #include <com/sun/star/awt/WindowDescriptor.hpp>
45 #include <com/sun/star/awt/WindowAttribute.hpp>
46 #include <com/sun/star/awt/PosSize.hpp>
47 #include <com/sun/star/util/XURLTransformer.hpp>
48 #include <com/sun/star/task/XInteractionAbort.hpp>
49 #include <com/sun/star/task/XInteractionApprove.hpp>
50 #include <com/sun/star/document/XInteractionFilterSelect.hpp>
51 #include <com/sun/star/task/ErrorCodeRequest.hpp>
52 #include <com/sun/star/ucb/InteractiveIOException.hpp>
53 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
54 #include <com/sun/star/frame/DispatchResultState.hpp>
55 #include <com/sun/star/lang/IllegalArgumentException.hpp>
56 #include <com/sun/star/lang/DisposedException.hpp>
57 #include <com/sun/star/util/CloseVetoException.hpp>
58 #include <com/sun/star/util/XCloseable.hpp>
59 #include <com/sun/star/document/MacroExecMode.hpp>
60 #include <com/sun/star/document/UpdateDocMode.hpp>
61 #include <com/sun/star/frame/XTerminateListener2.hpp>
62 
63 #include <comphelper/numberedcollection.hxx>
64 #include <comphelper/sequence.hxx>
65 #include <comphelper/lok.hxx>
66 #include <cppuhelper/supportsservice.hxx>
67 #include <rtl/instance.hxx>
68 #include <vcl/svapp.hxx>
69 #include <desktop/crashreport.hxx>
70 #include <vcl/scheduler.hxx>
71 #include <sal/log.hxx>
72 #include <rtl/ustrbuf.hxx>
73 
74 #include <vcl/errinf.hxx>
75 #include <unotools/configmgr.hxx>
76 
77 namespace framework{
78 
79 enum PropHandle {
80     ActiveFrame, DispatchRecorderSupplier, IsPlugged, SuspendQuickstartVeto,
81     Title };
82 
getImplementationName()83 OUString SAL_CALL Desktop::getImplementationName()
84 {
85     return "com.sun.star.comp.framework.Desktop";
86 }
87 
supportsService(OUString const & ServiceName)88 sal_Bool SAL_CALL Desktop::supportsService(OUString const & ServiceName)
89 {
90     return cppu::supportsService(this, ServiceName);
91 }
92 
getSupportedServiceNames()93 css::uno::Sequence<OUString> SAL_CALL Desktop::getSupportedServiceNames()
94 {
95     return { "com.sun.star.frame.Desktop" };
96 }
97 
constructorInit()98 void Desktop::constructorInit()
99 {
100     // Initialize a new XFrames-helper-object to handle XIndexAccess and XElementAccess.
101     // We hold member as reference ... not as pointer too!
102     // Attention: We share our frame container with this helper. Container is threadsafe himself ... So I think we can do that.
103     // But look on dispose() for right order of deinitialization.
104     OFrames* pFramesHelper = new OFrames( this, &m_aChildTaskContainer );
105     m_xFramesHelper.set( static_cast< ::cppu::OWeakObject* >(pFramesHelper), css::uno::UNO_QUERY );
106 
107     // Initialize a new dispatchhelper-object to handle dispatches.
108     // We use these helper as slave for our interceptor helper ... not directly!
109     // But he is event listener on THIS instance!
110     DispatchProvider* pDispatchHelper = new DispatchProvider( m_xContext, this );
111     css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( static_cast< ::cppu::OWeakObject* >(pDispatchHelper), css::uno::UNO_QUERY );
112 
113     // Initialize a new interception helper object to handle dispatches and implement an interceptor mechanism.
114     // Set created dispatch provider as slowest slave of it.
115     // Hold interception helper by reference only - not by pointer!
116     // So it's easier to destroy it.
117     InterceptionHelper* pInterceptionHelper = new InterceptionHelper( this, xDispatchProvider );
118     m_xDispatchHelper.set( static_cast< ::cppu::OWeakObject* >(pInterceptionHelper), css::uno::UNO_QUERY );
119 
120     OUString sUntitledPrefix = FwkResId(STR_UNTITLED_DOCUMENT) + " ";
121 
122     ::comphelper::NumberedCollection* pNumbers = new ::comphelper::NumberedCollection ();
123     m_xTitleNumberGenerator.set(static_cast< ::cppu::OWeakObject* >(pNumbers), css::uno::UNO_QUERY_THROW);
124     pNumbers->setOwner          ( static_cast< ::cppu::OWeakObject* >(this) );
125     pNumbers->setUntitledPrefix ( sUntitledPrefix );
126 
127     // Safe impossible cases
128     // We can't work without this helper!
129     SAL_WARN_IF( !m_xFramesHelper.is(), "fwk.desktop", "Desktop::Desktop(): Frames helper is not valid. XFrames, XIndexAccess and XElementAccess are not supported!");
130     SAL_WARN_IF( !m_xDispatchHelper.is(), "fwk.desktop", "Desktop::Desktop(): Dispatch helper is not valid. XDispatch will not work correctly!" );
131 
132     // Enable object for real working!
133     // Otherwise all calls will be rejected ...
134     m_aTransactionManager.setWorkingMode( E_WORK );
135 }
136 
137 /*-************************************************************************************************************
138     @short      standard constructor to create instance by factory
139     @descr      This constructor initialize a new instance of this class by valid factory,
140                 and will be set valid values on his member and baseclasses.
141 
142     @attention  a)  Don't use your own reference during a UNO-Service-ctor! There is no guarantee, that you
143                     will get over this. (e.g. using of your reference as parameter to initialize some member)
144                     Do such things in DEFINE_INIT_SERVICE() method, which is called automatically after your ctor!!!
145                 b)  Baseclass OBroadcastHelper is a typedef in namespace cppu!
146                     The microsoft compiler has some problems to handle it right BY using namespace explicitly ::cppu::OBroadcastHelper.
147                     If we write it without a namespace or expand the typedef to OBroadcastHelperVar<...> -> it will be OK!?
148                     I don't know why! (other compiler not tested .. but it works!)
149 
150     @seealso    method DEFINE_INIT_SERVICE()
151 
152     @param      "xFactory" is the multi service manager, which create this instance.
153                 The value must be different from NULL!
154     @onerror    We throw an ASSERT in debug version or do nothing in release version.
155 *//*-*************************************************************************************************************/
Desktop(const css::uno::Reference<css::uno::XComponentContext> & xContext)156 Desktop::Desktop( const css::uno::Reference< css::uno::XComponentContext >& xContext )
157         :   TransactionBase         (                                               )
158         ,   Desktop_BASE            ( m_aMutex )
159         ,   cppu::OPropertySetHelper( cppu::WeakComponentImplHelperBase::rBHelper   )
160         // Init member
161         ,   m_bIsTerminated         ( false                                     )   // see dispose() for further information!
162         ,   m_bSession              ( false                                         )
163         ,   m_xContext              ( xContext                                      )
164         ,   m_aChildTaskContainer   (                                               )
165         ,   m_aListenerContainer    ( m_aMutex )
166         ,   m_xFramesHelper         (                                               )
167         ,   m_xDispatchHelper       (                                               )
168         ,   m_eLoadState            ( E_NOTSET                                      )
169         ,   m_bSuspendQuickstartVeto( false                                     )
170         ,   m_sName                 (                                               )
171         ,   m_sTitle                (                                               )
172         ,   m_xDispatchRecorderSupplier(                                            )
173         ,   m_xPipeTerminator       (                                               )
174         ,   m_xQuickLauncher        (                                               )
175         ,   m_xStarBasicQuitGuard   (                                               )
176         ,   m_xSWThreadManager      (                                               )
177         ,   m_xSfxTerminator        (                                               )
178         ,   m_xTitleNumberGenerator (                                               )
179 {
180 }
181 
182 /*-************************************************************************************************************
183     @short      standard destructor
184     @descr      This one do NOTHING! Use dispose() instead of this.
185 
186     @seealso    method dispose()
187 *//*-*************************************************************************************************************/
~Desktop()188 Desktop::~Desktop()
189 {
190     SAL_WARN_IF( !m_bIsTerminated, "fwk.desktop", "Desktop not terminated before being destructed" );
191     SAL_WARN_IF( m_aTransactionManager.getWorkingMode()!=E_CLOSE, "fwk.desktop", "Desktop::~Desktop(): Who forgot to dispose this service?" );
192 }
193 
queryInterface(const css::uno::Type & _rType)194 css::uno::Any SAL_CALL Desktop::queryInterface( const css::uno::Type& _rType )
195 {
196     css::uno::Any aRet = Desktop_BASE::queryInterface( _rType );
197     if ( !aRet.hasValue() )
198         aRet = OPropertySetHelper::queryInterface( _rType );
199     return aRet;
200 }
201 
getTypes()202 css::uno::Sequence< css::uno::Type > SAL_CALL Desktop::getTypes(  )
203 {
204     return comphelper::concatSequences(
205         Desktop_BASE::getTypes(),
206         ::cppu::OPropertySetHelper::getTypes()
207     );
208 }
209 
terminate()210 sal_Bool SAL_CALL Desktop::terminate()
211 {
212     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
213 
214     SolarMutexClearableGuard aReadLock;
215 
216     css::uno::Reference< css::frame::XTerminateListener > xPipeTerminator    = m_xPipeTerminator;
217     css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher     = m_xQuickLauncher;
218     css::uno::Reference< css::frame::XTerminateListener > xStarBasicQuitGuard = m_xStarBasicQuitGuard;
219     css::uno::Reference< css::frame::XTerminateListener > xSWThreadManager   = m_xSWThreadManager;
220     css::uno::Reference< css::frame::XTerminateListener > xSfxTerminator     = m_xSfxTerminator;
221 
222     css::lang::EventObject                                aEvent             ( static_cast< ::cppu::OWeakObject* >(this) );
223     bool                                                  bAskQuickStart     = !m_bSuspendQuickstartVeto;
224 
225     aReadLock.clear();
226 
227     // try to close all open frames.
228     // Allow using of any UI ... because Desktop.terminate() was designed as UI functionality in the past.
229     bool bRestartableMainLoop = Application::IsEventTestingModeEnabled() ||
230                                 comphelper::LibreOfficeKit::isActive();
231     bool bFramesClosed = impl_closeFrames(!bRestartableMainLoop);
232 
233     // Ask normal terminate listener. They could stop terminating the process.
234     Desktop::TTerminateListenerList lCalledTerminationListener;
235     bool bVeto = false;
236     impl_sendQueryTerminationEvent(lCalledTerminationListener, bVeto);
237     if ( bVeto )
238     {
239         impl_sendCancelTerminationEvent(lCalledTerminationListener);
240         return false;
241     }
242 
243     if (bRestartableMainLoop)
244     {
245 #ifndef IOS // or ANDROID?
246         // In the iOS app, posting the ImplQuitMsg user event will be too late, it will not be handled during the
247         // lifetime of the current document, but handled for the next document opened, which thus will break horribly.
248         Application::Quit();
249 #endif
250         return true;
251     }
252     if ( ! bFramesClosed )
253     {
254         impl_sendCancelTerminationEvent(lCalledTerminationListener);
255         return false;
256     }
257 
258     // Normal listener had no problem ...
259     // all frames was closed ...
260     // now it's time to ask our specialized listener.
261     // They are handled these way because they wish to hinder the office on termination
262     // but they wish also closing of all frames.
263 
264     // Note further:
265     //    We shouldn't ask quicklauncher in case it was allowed from outside only.
266     //    This is special trick to "ignore existing quick starter" for debug purposes.
267 
268     // Attention:
269     // Order of called listener is important!
270     // Some of them are harmless,-)
271     // but some can be dangerous. E.g. it would be dangerous if we close our pipe
272     // and don't terminate in real because another listener throws a veto exception .-)
273 
274     bool bTerminate = false;
275     try
276     {
277         if( bAskQuickStart && xQuickLauncher.is() )
278         {
279             xQuickLauncher->queryTermination( aEvent );
280             lCalledTerminationListener.push_back( xQuickLauncher );
281         }
282 
283         if ( xStarBasicQuitGuard.is() )
284         {
285             xStarBasicQuitGuard->queryTermination( aEvent );
286             lCalledTerminationListener.push_back( xStarBasicQuitGuard );
287         }
288 
289         if ( xSWThreadManager.is() )
290         {
291             xSWThreadManager->queryTermination( aEvent );
292             lCalledTerminationListener.push_back( xSWThreadManager );
293         }
294 
295         if ( xPipeTerminator.is() )
296         {
297             xPipeTerminator->queryTermination( aEvent );
298             lCalledTerminationListener.push_back( xPipeTerminator );
299         }
300 
301         if ( xSfxTerminator.is() )
302         {
303             xSfxTerminator->queryTermination( aEvent );
304             lCalledTerminationListener.push_back( xSfxTerminator );
305         }
306 
307         bTerminate = true;
308     }
309     catch(const css::frame::TerminationVetoException&)
310     {
311         bTerminate = false;
312     }
313 
314     if ( ! bTerminate )
315         impl_sendCancelTerminationEvent(lCalledTerminationListener);
316     else
317     {
318         // "Protect" us against dispose before terminate calls!
319         // see dispose() for further information.
320         /* SAFE AREA --------------------------------------------------------------------------------------- */
321         SolarMutexClearableGuard aWriteLock;
322         CrashReporter::addKeyValue("ShutDown", OUString::boolean(true), CrashReporter::Write);
323         m_bIsTerminated = true;
324         aWriteLock.clear();
325         /* UNSAFE AREA ------------------------------------------------------------------------------------- */
326 
327         // The clipboard listener needs to be the first. It can create copies of the
328         // existing document which needs basically all the available infrastructure.
329         {
330             SolarMutexResettableGuard aGuard;
331             impl_sendTerminateToClipboard();
332             aGuard.clear();
333             impl_sendNotifyTerminationEvent();
334             aGuard.reset();
335             Scheduler::ProcessEventsToIdle();
336         }
337 
338         if( bAskQuickStart && xQuickLauncher.is() )
339         {
340             xQuickLauncher->notifyTermination( aEvent );
341         }
342 
343         if ( xStarBasicQuitGuard.is() )
344             xStarBasicQuitGuard->notifyTermination( aEvent );
345 
346         if ( xSWThreadManager.is() )
347             xSWThreadManager->notifyTermination( aEvent );
348 
349         if ( xPipeTerminator.is() )
350             xPipeTerminator->notifyTermination( aEvent );
351 
352         // we need a copy here as the notifyTermination call might cause a removeTerminateListener call
353         std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners = m_xComponentDllListeners;
354         for (auto& xListener : xComponentDllListeners)
355         {
356             xListener->notifyTermination(aEvent);
357         }
358         m_xComponentDllListeners.clear();
359 
360         // Must be really the last listener to be called.
361         // Because it shutdown the whole process asynchronous !
362         if ( xSfxTerminator.is() )
363             xSfxTerminator->notifyTermination( aEvent );
364     }
365 
366     return bTerminate;
367 }
368 
369 namespace
370 {
371     class QuickstartSuppressor
372     {
373         Desktop* const m_pDesktop;
374         css::uno::Reference< css::frame::XTerminateListener > m_xQuickLauncher;
375         public:
QuickstartSuppressor(Desktop * const pDesktop,css::uno::Reference<css::frame::XTerminateListener> const & xQuickLauncher)376             QuickstartSuppressor(Desktop* const pDesktop, css::uno::Reference< css::frame::XTerminateListener > const & xQuickLauncher)
377                 : m_pDesktop(pDesktop)
378                 , m_xQuickLauncher(xQuickLauncher)
379             {
380                 SAL_INFO("fwk.desktop", "temporary removing Quickstarter");
381                 if(m_xQuickLauncher.is())
382                     m_pDesktop->removeTerminateListener(m_xQuickLauncher);
383             }
~QuickstartSuppressor()384             ~QuickstartSuppressor()
385             {
386                 SAL_INFO("fwk.desktop", "readding Quickstarter");
387                 if(m_xQuickLauncher.is())
388                     m_pDesktop->addTerminateListener(m_xQuickLauncher);
389             }
390     };
391 }
392 
terminateQuickstarterToo()393 bool Desktop::terminateQuickstarterToo()
394 {
395     QuickstartSuppressor aQuickstartSuppressor(this, m_xQuickLauncher);
396     m_bSession = true;
397     return terminate();
398 }
399 
addTerminateListener(const css::uno::Reference<css::frame::XTerminateListener> & xListener)400 void SAL_CALL Desktop::addTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
401 {
402     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
403 
404     css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
405     if ( xInfo.is() )
406     {
407         OUString sImplementationName = xInfo->getImplementationName();
408 
409         SolarMutexGuard g;
410 
411         if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
412         {
413             m_xSfxTerminator = xListener;
414             return;
415         }
416         if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
417         {
418             m_xPipeTerminator = xListener;
419             return;
420         }
421         if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
422         {
423             m_xQuickLauncher = xListener;
424             return;
425         }
426         if( sImplementationName == "com.sun.star.comp.svx.StarBasicQuitGuard" )
427         {
428             m_xStarBasicQuitGuard = xListener;
429             return;
430         }
431         if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
432         {
433             m_xSWThreadManager = xListener;
434             return;
435         }
436         else if ( sImplementationName == "com.sun.star.comp.ComponentDLLListener" )
437         {
438             m_xComponentDllListeners.push_back(xListener);
439             return;
440         }
441     }
442 
443     // No lock required... container is threadsafe by itself.
444     m_aListenerContainer.addInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
445 }
446 
removeTerminateListener(const css::uno::Reference<css::frame::XTerminateListener> & xListener)447 void SAL_CALL Desktop::removeTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
448 {
449     TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
450 
451     css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
452     if ( xInfo.is() )
453     {
454         OUString sImplementationName = xInfo->getImplementationName();
455 
456         SolarMutexGuard g;
457 
458         if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
459         {
460             m_xSfxTerminator.clear();
461             return;
462         }
463 
464         if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
465         {
466             m_xPipeTerminator.clear();
467             return;
468         }
469 
470         if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
471         {
472             m_xQuickLauncher.clear();
473             return;
474         }
475 
476         if( sImplementationName == "com.sun.star.comp.svx.StarBasicQuitGuard" )
477         {
478             m_xStarBasicQuitGuard.clear();
479             return;
480         }
481 
482         if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
483         {
484             m_xSWThreadManager.clear();
485             return;
486         }
487         else if (sImplementationName == "com.sun.star.comp.ComponentDLLListener")
488         {
489             m_xComponentDllListeners.erase(
490                     std::remove(m_xComponentDllListeners.begin(), m_xComponentDllListeners.end(), xListener),
491                     m_xComponentDllListeners.end());
492             return;
493         }
494     }
495 
496     // No lock required ... container is threadsafe by itself.
497     m_aListenerContainer.removeInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
498 }
499 
500 /*-************************************************************************************************************
501     @interface  XDesktop
502     @short      get access to create enumerations of all current components
503     @descr      You will be the owner of the returned object and must delete it if you don't use it again.
504 
505     @seealso    class TasksAccess
506     @seealso    class TasksEnumeration
507     @return     A reference to an XEnumerationAccess-object.
508 
509     @onerror    We return a null-reference.
510     @threadsafe yes
511 *//*-*************************************************************************************************************/
getComponents()512 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getComponents()
513 {
514     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
515     // Register transaction and reject wrong calls.
516     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
517 
518     // We use a helper class OComponentAccess to have access on all child components.
519     // Create it on demand and return it as a reference.
520     OComponentAccess* pAccess = new OComponentAccess( this );
521     css::uno::Reference< css::container::XEnumerationAccess > xAccess( static_cast< ::cppu::OWeakObject* >(pAccess), css::uno::UNO_QUERY );
522     return xAccess;
523 }
524 
525 /*-************************************************************************************************************
526     @interface  XDesktop
527     @short      return the current active component
528     @descr      The most current component is the window, model or the controller of the current active frame.
529 
530     @seealso    method getCurrentFrame()
531     @seealso    method impl_getFrameComponent()
532     @return     A reference to the component.
533 
534     @onerror    We return a null-reference.
535     @threadsafe yes
536 *//*-*************************************************************************************************************/
getCurrentComponent()537 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::getCurrentComponent()
538 {
539     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
540     // Register transaction and reject wrong calls.
541     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
542 
543     // Set return value if method failed.
544     css::uno::Reference< css::lang::XComponent > xComponent;
545 
546     // Get reference to current frame ...
547     // ... get component of this frame ... (It can be the window, the model or the controller.)
548     // ... and return the result.
549     css::uno::Reference< css::frame::XFrame > xCurrentFrame = getCurrentFrame();
550     if( xCurrentFrame.is() )
551     {
552         xComponent = impl_getFrameComponent( xCurrentFrame );
553     }
554     return xComponent;
555 }
556 
557 /*-************************************************************************************************************
558     @interface  XDesktop
559     @short      return the current active frame in hierarchy
560     @descr      There can be more than one different active paths in our frame hierarchy. But only one of them
561                 could be the most active frame (normal he has the focus).
562                 Don't mix it with getActiveFrame()! That will return our current active frame, which must be
563                 a direct child of us and should be a part(!) of an active path.
564 
565     @seealso    method getActiveFrame()
566     @return     A valid reference, if there is an active frame.
567                 A null reference , otherwise.
568 
569     @onerror    We return a null reference.
570     @threadsafe yes
571 *//*-*************************************************************************************************************/
getCurrentFrame()572 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getCurrentFrame()
573 {
574     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
575     // Register transaction and reject wrong calls.
576     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
577 
578     // Start search with our direct active frame (if it exist!).
579     // Search on his children for other active frames too.
580     // Stop if no one could be found and return last of found ones.
581     css::uno::Reference< css::frame::XFramesSupplier > xLast( getActiveFrame(), css::uno::UNO_QUERY );
582     if( xLast.is() )
583     {
584         css::uno::Reference< css::frame::XFramesSupplier > xNext( xLast->getActiveFrame(), css::uno::UNO_QUERY );
585         while( xNext.is() )
586         {
587             xLast = xNext;
588             xNext.set( xNext->getActiveFrame(), css::uno::UNO_QUERY );
589         }
590     }
591     return xLast;
592 }
593 
594 /*-************************************************************************************************************
595     @interface  XComponentLoader
596     @short      try to load given URL into a task
597     @descr      You can give us some information about the content, which you will load into a frame.
598                 We search or create this target for you, make a type detection of given URL and try to load it.
599                 As result of this operation we return the new created component or nothing, if loading failed.
600     @param      "sURL"              , URL, which represent the content
601     @param      "sTargetFrameName"  , name of target frame or special value like "_self", "_blank" ...
602     @param      "nSearchFlags"      , optional arguments for frame search, if target isn't a special one
603     @param      "lArguments"        , optional arguments for loading
604     @return     A valid component reference, if loading was successful.
605                 A null reference otherwise.
606 
607     @onerror    We return a null reference.
608     @threadsafe yes
609 *//*-*************************************************************************************************************/
loadComponentFromURL(const OUString & sURL,const OUString & sTargetFrameName,sal_Int32 nSearchFlags,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)610 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::loadComponentFromURL( const OUString&                                 sURL            ,
611                                                                                      const OUString&                                 sTargetFrameName,
612                                                                                            sal_Int32                                        nSearchFlags    ,
613                                                                                      const css::uno::Sequence< css::beans::PropertyValue >& lArguments      )
614 {
615     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
616     // Register transaction and reject wrong calls.
617     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
618     SAL_INFO( "fwk.desktop", "loadComponentFromURL" );
619 
620     css::uno::Reference< css::frame::XComponentLoader > xThis(static_cast< css::frame::XComponentLoader* >(this), css::uno::UNO_QUERY);
621 
622     return LoadEnv::loadComponentFromURL(xThis, m_xContext, sURL, sTargetFrameName, nSearchFlags, lArguments);
623 }
624 
625 /*-************************************************************************************************************
626     @interface  XTasksSupplier
627     @short      get access to create enumerations of our taskchildren
628     @descr      Direct children of desktop are tasks every time.
629                 Call these method to could create enumerations of it.
630 
631 But; Don't forget - you will be the owner of returned object and must release it!
632                 We use a helper class to implement the access interface. They hold a weakreference to us.
633                 It can be, that the desktop is dead - but not your tasksaccess-object! Then they will do nothing!
634                 You can't create enumerations then.
635 
636     @attention  Normally we don't need any lock here. We don't work on internal member!
637 
638     @seealso    class TasksAccess
639     @return     A reference to an accessobject, which can create enumerations of our childtasks.
640 
641     @onerror    A null reference is returned.
642     @threadsafe yes
643 *//*-*************************************************************************************************************/
getTasks()644 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getTasks()
645 {
646     SAL_INFO("fwk.desktop", "Desktop::getTasks(): Use of obsolete interface XTaskSupplier");
647     return nullptr;
648 }
649 
650 /*-************************************************************************************************************
651     @interface  XTasksSupplier
652     @short      return current active task of our direct children
653     @descr      Desktop children are tasks only ! If we have an active path from desktop
654                 as top to any frame on bottom, we must have an active direct child. His reference is returned here.
655 
656     @attention  a)  Do not confuse it with getCurrentFrame()! The current frame don't must one of our direct children.
657                     It can be every frame in subtree and must have the focus (Is the last one of an active path!).
658                 b)  We don't need any lock here. Our container is threadsafe himself and live, if we live!
659 
660     @seealso    method getCurrentFrame()
661     @return     A reference to our current active taskchild.
662 
663     @onerror    A null reference is returned.
664     @threadsafe yes
665 *//*-*************************************************************************************************************/
getActiveTask()666 css::uno::Reference< css::frame::XTask > SAL_CALL Desktop::getActiveTask()
667 {
668     SAL_INFO("fwk.desktop", "Desktop::getActiveTask(): Use of obsolete interface XTaskSupplier");
669     return nullptr;
670 }
671 
672 /*-************************************************************************************************************
673     @interface  XDispatchProvider
674     @short      search a dispatcher for given URL
675     @descr      We use a helper implementation (class DispatchProvider) to do so.
676                 So we don't must implement this algorithm twice!
677 
678     @attention  We don't need any lock here. Our helper is threadsafe himself and live, if we live!
679 
680     @seealso    class DispatchProvider
681 
682     @param      "aURL"              , URL to dispatch
683     @param      "sTargetFrameName"  , name of target frame, who should dispatch these URL
684     @param      "nSearchFlags"      , flags to regulate the search
685     @param      "lQueries"          , list of queryDispatch() calls!
686     @return     A reference or list of founded dispatch objects for these URL.
687 
688     @onerror    A null reference is returned.
689     @threadsafe yes
690 *//*-*************************************************************************************************************/
queryDispatch(const css::util::URL & aURL,const OUString & sTargetFrameName,sal_Int32 nSearchFlags)691 css::uno::Reference< css::frame::XDispatch > SAL_CALL Desktop::queryDispatch( const css::util::URL&  aURL             ,
692                                                                               const OUString& sTargetFrameName ,
693                                                                                     sal_Int32        nSearchFlags     )
694 {
695     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
696     // Register transaction and reject wrong calls.
697     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
698 
699     // Remove uno and cmd protocol part as we want to support both of them. We store only the command part
700     // in our hash map. All other protocols are stored with the protocol part.
701     OUString aCommand( aURL.Main );
702     if ( aURL.Protocol.equalsIgnoreAsciiCase(".uno:") )
703         aCommand = aURL.Path;
704 
705     if (!m_xCommandOptions && !utl::ConfigManager::IsFuzzing())
706         m_xCommandOptions.reset(new SvtCommandOptions);
707 
708     // Make std::unordered_map lookup if the current URL is in the disabled list
709     if (m_xCommandOptions && m_xCommandOptions->Lookup(SvtCommandOptions::CMDOPTION_DISABLED, aCommand))
710         return css::uno::Reference< css::frame::XDispatch >();
711     else
712     {
713         // We use a helper to support these interface and an interceptor mechanism.
714         // Our helper is threadsafe by himself!
715         return m_xDispatchHelper->queryDispatch( aURL, sTargetFrameName, nSearchFlags );
716     }
717 }
718 
queryDispatches(const css::uno::Sequence<css::frame::DispatchDescriptor> & lQueries)719 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL Desktop::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lQueries )
720 {
721     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
722     // Register transaction and reject wrong calls.
723     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
724 
725     return m_xDispatchHelper->queryDispatches( lQueries );
726 }
727 
728 /*-************************************************************************************************************
729     @interface  XDispatchProviderInterception
730     @short      supports registration/deregistration of interception objects, which
731                 are interested on special dispatches.
732 
733     @descr      It's really provided by an internal helper, which is used inside the dispatch API too.
734     @param      xInterceptor
735                 the interceptor object, which wishes to be (de)registered.
736 
737     @threadsafe yes
738 *//*-*************************************************************************************************************/
registerDispatchProviderInterceptor(const css::uno::Reference<css::frame::XDispatchProviderInterceptor> & xInterceptor)739 void SAL_CALL Desktop::registerDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
740 {
741     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
742 
743     css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
744     xInterceptionHelper->registerDispatchProviderInterceptor( xInterceptor );
745 }
746 
releaseDispatchProviderInterceptor(const css::uno::Reference<css::frame::XDispatchProviderInterceptor> & xInterceptor)747 void SAL_CALL Desktop::releaseDispatchProviderInterceptor ( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
748 {
749     TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
750 
751     css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
752     xInterceptionHelper->releaseDispatchProviderInterceptor( xInterceptor );
753 }
754 
755 /*-************************************************************************************************************
756     @interface  XFramesSupplier
757     @short      return access to append or remove children on desktop
758     @descr      We don't implement these interface directly. We use a helper class to do this.
759                 If you wish to add or delete children to/from the container, call these method to get
760                 a reference to the helper.
761 
762     @attention  Helper is threadsafe himself. So we don't need any lock here.
763 
764     @seealso    class OFrames
765     @return     A reference to the helper.
766 
767     @onerror    A null reference is returned.
768     @threadsafe yes
769 *//*-*************************************************************************************************************/
getFrames()770 css::uno::Reference< css::frame::XFrames > SAL_CALL Desktop::getFrames()
771 {
772     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
773     // Register transaction and reject wrong calls.
774     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
775 
776     return m_xFramesHelper;
777 }
778 
779 /*-************************************************************************************************************
780     @interface  XFramesSupplier
781     @short      set/get the current active child frame
782     @descr      It must be a task. Direct children of desktop are tasks only! No frames are accepted.
783                 We don't save this information directly in this class. We use our container-helper
784                 to do that.
785 
786     @attention  Helper is threadsafe himself. So we don't need any lock here.
787 
788     @seealso    class OFrameContainer
789 
790     @param      "xFrame", new active frame (must be valid!)
791     @return     A reference to our current active childtask, if anyone exist.
792 
793     @onerror    A null reference is returned.
794     @threadsafe yes
795 *//*-*************************************************************************************************************/
setActiveFrame(const css::uno::Reference<css::frame::XFrame> & xFrame)796 void SAL_CALL Desktop::setActiveFrame( const css::uno::Reference< css::frame::XFrame >& xFrame )
797 {
798     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
799     // Register transaction and reject wrong calls.
800     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
801 
802     // Get old active frame first.
803     // If nothing will change - do nothing!
804     // Otherwise set new active frame ...
805     // and deactivate last frame.
806     // It's necessary for our FrameActionEvent listener on a frame!
807     css::uno::Reference< css::frame::XFrame > xLastActiveChild = m_aChildTaskContainer.getActive();
808     if( xLastActiveChild != xFrame )
809     {
810         m_aChildTaskContainer.setActive( xFrame );
811         if( xLastActiveChild.is() )
812         {
813             xLastActiveChild->deactivate();
814         }
815     }
816 }
817 
getActiveFrame()818 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getActiveFrame()
819 {
820     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
821     // Register transaction and reject wrong calls.
822     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
823 
824     return m_aChildTaskContainer.getActive();
825 }
826 
827 /*
828     @interface  XFrame
829     @short      non implemented methods!
830     @descr      Some method make no sense for our desktop! He has no window or parent or ...
831                 So we should implement it empty and warn programmer, if he use it!
832 */
initialize(const css::uno::Reference<css::awt::XWindow> &)833 void SAL_CALL Desktop::initialize( const css::uno::Reference< css::awt::XWindow >& )
834 {
835 }
836 
getContainerWindow()837 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getContainerWindow()
838 {
839     return css::uno::Reference< css::awt::XWindow >();
840 }
841 
setCreator(const css::uno::Reference<css::frame::XFramesSupplier> &)842 void SAL_CALL Desktop::setCreator( const css::uno::Reference< css::frame::XFramesSupplier >& /*xCreator*/ )
843 {
844 }
845 
getCreator()846 css::uno::Reference< css::frame::XFramesSupplier > SAL_CALL Desktop::getCreator()
847 {
848     return css::uno::Reference< css::frame::XFramesSupplier >();
849 }
850 
getName()851 OUString SAL_CALL Desktop::getName()
852 {
853     SolarMutexGuard g;
854     return m_sName;
855 }
856 
setName(const OUString & sName)857 void SAL_CALL Desktop::setName( const OUString& sName )
858 {
859     SolarMutexGuard g;
860     m_sName = sName;
861 }
862 
isTop()863 sal_Bool SAL_CALL Desktop::isTop()
864 {
865     return true;
866 }
867 
activate()868 void SAL_CALL Desktop::activate()
869 {
870     // Desktop is active always... but sometimes our frames try to activate
871     // the complete path from bottom to top... And our desktop is the topest frame :-(
872     // So - please don't show any assertions here. Do nothing!
873 }
874 
deactivate()875 void SAL_CALL Desktop::deactivate()
876 {
877     // Desktop is active always... but sometimes our frames try to deactivate
878     // the complete path from bottom to top... And our desktop is the topest frame :-(
879     // So - please don't show any assertions here. Do nothing!
880 }
881 
isActive()882 sal_Bool SAL_CALL Desktop::isActive()
883 {
884     return true;
885 }
886 
setComponent(const css::uno::Reference<css::awt::XWindow> &,const css::uno::Reference<css::frame::XController> &)887 sal_Bool SAL_CALL Desktop::setComponent( const css::uno::Reference< css::awt::XWindow >&       /*xComponentWindow*/ ,
888                                          const css::uno::Reference< css::frame::XController >& /*xController*/      )
889 {
890     return false;
891 }
892 
getComponentWindow()893 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getComponentWindow()
894 {
895     return css::uno::Reference< css::awt::XWindow >();
896 }
897 
getController()898 css::uno::Reference< css::frame::XController > SAL_CALL Desktop::getController()
899 {
900     return css::uno::Reference< css::frame::XController >();
901 }
902 
contextChanged()903 void SAL_CALL Desktop::contextChanged()
904 {
905 }
906 
addFrameActionListener(const css::uno::Reference<css::frame::XFrameActionListener> &)907 void SAL_CALL Desktop::addFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
908 {
909 }
910 
911 //   css::frame::XFrame
removeFrameActionListener(const css::uno::Reference<css::frame::XFrameActionListener> &)912 void SAL_CALL Desktop::removeFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
913 {
914 }
915 
916 /*-************************************************************************************************************
917     @interface  XFrame
918     @short      try to find a frame with special parameters
919     @descr      This method searches for a frame with the specified name.
920                 Frames may contain other frames (e.g. a frameset) and may
921                 be contained in other frames. This hierarchy is searched by
922                 this method.
923                 First some special names are taken into account, i.e. "",
924                 "_self", "_top", "_parent" etc. The FrameSearchFlags are ignored
925                 when comparing these names with aTargetFrameName, further steps are
926                 controlled by the FrameSearchFlags. If allowed, the name of the frame
927                 itself is compared with the desired one, then ( again if allowed )
928                 the method findFrame is called for all children of the frame.
929                 If no Frame with the given name is found until the top frames container,
930                 a new top Frame is created, if this is allowed by a special
931                 FrameSearchFlag. The new Frame also gets the desired name.
932                 We use a helper to get right search direction and react in a right manner.
933 
934     @seealso    class TargetFinder
935 
936     @param      "sTargetFrameName"  , name of searched frame
937     @param      "nSearchFlags"      , flags to regulate search
938     @return     A reference to an existing frame in hierarchy, if it exist.
939 
940     @onerror    A null reference is returned.
941     @threadsafe yes
942 *//*-*************************************************************************************************************/
findFrame(const OUString & sTargetFrameName,sal_Int32 nSearchFlags)943 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::findFrame( const OUString& sTargetFrameName ,
944                                                                              sal_Int32        nSearchFlags     )
945 {
946     css::uno::Reference< css::frame::XFrame > xTarget;
947 
948     // 0) Ignore wrong parameter!
949     //    We don't support search for following special targets.
950     //    If we reject these requests, we must not check for such names
951     //    in following code again and again. If we do not, so wrong
952     //    search results can occur!
953 
954     if (
955         (sTargetFrameName==SPECIALTARGET_DEFAULT  )   ||    // valid for dispatches - not for findFrame()!
956         (sTargetFrameName==SPECIALTARGET_PARENT   )   ||    // we have no parent by definition
957         (sTargetFrameName==SPECIALTARGET_BEAMER   )         // beamer frames are allowed as child of tasks only -
958                                                             // and they exist more than ones. We have no idea which our sub tasks is the right one
959        )
960     {
961         return nullptr;
962     }
963 
964     // I) check for special defined targets first which must be handled exclusive.
965     //    force using of "if() else if() ..."
966 
967     // I.I) "_blank"
968     //  create a new task as child of this desktop instance
969     //  Note: Used helper TaskCreator use us automatically ...
970 
971     if ( sTargetFrameName==SPECIALTARGET_BLANK )
972     {
973         TaskCreator aCreator( m_xContext );
974         xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
975     }
976 
977     // I.II) "_top"
978     //  We are top by definition
979 
980     else if ( sTargetFrameName==SPECIALTARGET_TOP )
981     {
982         xTarget = this;
983     }
984 
985     // I.III) "_self", ""
986     //  This mean this "frame" in every case.
987 
988     else if (
989              ( sTargetFrameName==SPECIALTARGET_SELF ) ||
990              ( sTargetFrameName.isEmpty()           )
991             )
992     {
993         xTarget = this;
994     }
995 
996     else
997     {
998 
999         // II) otherwise use optional given search flags
1000         //  force using of combinations of such flags. means no "else" part of use if() statements.
1001         //  But we ust break further searches if target was already found.
1002         //  Order of using flags is fix: SELF - CHILDREN - SIBLINGS - PARENT
1003         //  TASK and CREATE are handled special.
1004         //  But note: Such flags are not valid for the desktop - especially SIBLINGS or PARENT.
1005 
1006         // II.I) SELF
1007         //  Check for right name. If it's the searched one return ourself - otherwise
1008         //  ignore this flag.
1009 
1010         if (
1011             (nSearchFlags &  css::frame::FrameSearchFlag::SELF)  &&
1012             (m_sName == sTargetFrameName)
1013            )
1014         {
1015             xTarget = this;
1016         }
1017 
1018         // II.II) TASKS
1019         //  This is a special flag. Normally it regulate search inside tasks and forbid access to parent trees.
1020         //  But the desktop exists outside such task trees. They are our sub trees. So the desktop implement
1021         //  a special feature: We use it to start search on our direct children only. That means we suppress
1022         //  search on ALL child frames. May that can be useful to get access on opened document tasks
1023         //  only without filter out all non really required sub frames ...
1024         //  Used helper method on our container doesn't create any frame - it's a search only.
1025 
1026         if (
1027             ( ! xTarget.is()                                  ) &&
1028             (nSearchFlags & css::frame::FrameSearchFlag::TASKS)
1029            )
1030         {
1031             xTarget = m_aChildTaskContainer.searchOnDirectChildrens(sTargetFrameName);
1032         }
1033 
1034         // II.III) CHILDREN
1035         //  Search on all children for the given target name.
1036         //  An empty name value can't occur here - because it must be already handled as "_self"
1037         //  before. Used helper function of container doesn't create any frame.
1038         //  It makes a deep search only.
1039 
1040         if (
1041             ( ! xTarget.is()                                     ) &&
1042             (nSearchFlags & css::frame::FrameSearchFlag::CHILDREN)
1043            )
1044         {
1045             xTarget = m_aChildTaskContainer.searchOnAllChildrens(sTargetFrameName);
1046         }
1047 
1048         // II.IV) CREATE
1049         //  If we haven't found any valid target frame by using normal flags - but user allowed us to create
1050         //  a new one ... we should do that. Used TaskCreator use us automatically as parent!
1051 
1052         if (
1053             ( ! xTarget.is()                                   )    &&
1054             (nSearchFlags & css::frame::FrameSearchFlag::CREATE)
1055            )
1056         {
1057             TaskCreator aCreator( m_xContext );
1058             xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
1059         }
1060     }
1061 
1062     return xTarget;
1063 }
1064 
disposing()1065 void SAL_CALL Desktop::disposing()
1066 {
1067     // Safe impossible cases
1068     // It's a programming error if dispose is called before terminate!
1069 
1070     // But if you just ignore the assertion (which happens in unit
1071     // tests for instance in sc/qa/unit) nothing bad happens.
1072     SAL_WARN_IF( !m_bIsTerminated, "fwk.desktop", "Desktop disposed before terminating it" );
1073 
1074     {
1075         SolarMutexGuard aWriteLock;
1076 
1077         {
1078             TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);
1079         }
1080 
1081         // Disable this instance for further work.
1082         // This will wait for all current running transactions ...
1083         // and reject all new incoming requests!
1084         m_aTransactionManager.setWorkingMode(E_BEFORECLOSE);
1085     }
1086 
1087     // Following lines of code can be called outside a synchronized block ...
1088     // Because our transaction manager will block all new requests to this object.
1089     // So nobody can use us any longer.
1090     // Exception: Only removing of listener will work ... and this code can't be dangerous.
1091 
1092     // First we have to kill all listener connections.
1093     // They might rely on our member and can hinder us on releasing them.
1094     css::uno::Reference< css::uno::XInterface > xThis ( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
1095     css::lang::EventObject                      aEvent( xThis );
1096     m_aListenerContainer.disposeAndClear( aEvent );
1097 
1098     // Clear our child task container and forget all task references hardly.
1099     // Normally all open document was already closed by our terminate() function before ...
1100     // New opened frames will have a problem now .-)
1101     m_aChildTaskContainer.clear();
1102 
1103     // Dispose our helper too.
1104     css::uno::Reference< css::lang::XEventListener > xFramesHelper( m_xFramesHelper, css::uno::UNO_QUERY );
1105     if( xFramesHelper.is() )
1106         xFramesHelper->disposing( aEvent );
1107 
1108     // At least clean up other member references.
1109     m_xDispatchHelper.clear();
1110     m_xFramesHelper.clear();
1111     m_xContext.clear();
1112 
1113     m_xPipeTerminator.clear();
1114     m_xQuickLauncher.clear();
1115     m_xStarBasicQuitGuard.clear();
1116     m_xSWThreadManager.clear();
1117 
1118     // we need a copy because the disposing might call the removeEventListener method
1119     std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners = m_xComponentDllListeners;
1120     for (auto& xListener: xComponentDllListeners)
1121     {
1122         xListener->disposing(aEvent);
1123     }
1124     xComponentDllListeners.clear();
1125     m_xComponentDllListeners.clear();
1126     m_xSfxTerminator.clear();
1127     m_xCommandOptions.reset();
1128 
1129     // From this point nothing will work further on this object ...
1130     // excepting our dtor() .-)
1131     m_aTransactionManager.setWorkingMode( E_CLOSE );
1132 }
1133 
1134 /*
1135     @interface  XComponent
1136     @short      add/remove listener for dispose events
1137     @descr      Add an event listener to this object, if you wish to get information
1138                 about our dying!
1139                 You must release this listener reference during your own disposing() method.
1140 
1141     @attention  Our container is threadsafe himself. So we don't need any lock here.
1142     @param      "xListener", reference to valid listener. We don't accept invalid values!
1143     @threadsafe yes
1144 */
addEventListener(const css::uno::Reference<css::lang::XEventListener> & xListener)1145 void SAL_CALL Desktop::addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1146 {
1147     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1148     // Safe impossible cases
1149     // Method not defined for all incoming parameter.
1150     SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::addEventListener(): Invalid parameter detected!" );
1151     // Register transaction and reject wrong calls.
1152     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1153 
1154     m_aListenerContainer.addInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1155 }
1156 
removeEventListener(const css::uno::Reference<css::lang::XEventListener> & xListener)1157 void SAL_CALL Desktop::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1158 {
1159     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1160     // Safe impossible cases
1161     // Method not defined for all incoming parameter.
1162     SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::removeEventListener(): Invalid parameter detected!" );
1163     // Register transaction and reject wrong calls.
1164     TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
1165 
1166     m_aListenerContainer.removeInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1167 }
1168 
1169 /*-************************************************************************************************************
1170     @interface  XDispatchResultListener
1171     @short      callback for dispatches
1172     @descr      To support our method "loadComponentFromURL()" we are listener on temp. created dispatcher.
1173                 They call us back in this method "statusChanged()". As source of given state event, they give us a
1174                 reference to the target frame, in which dispatch was loaded! So we can use it to return his component
1175                 to caller! If no target exist ... ??!!
1176 
1177     @seealso    method loadComponentFromURL()
1178 
1179     @param      "aEvent", state event which (hopefully) valid information
1180     @threadsafe yes
1181 *//*-*************************************************************************************************************/
dispatchFinished(const css::frame::DispatchResultEvent & aEvent)1182 void SAL_CALL Desktop::dispatchFinished( const css::frame::DispatchResultEvent& aEvent )
1183 {
1184     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1185     // Register transaction and reject wrong calls.
1186     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1187 
1188     SolarMutexGuard g;
1189     if( m_eLoadState != E_INTERACTION )
1190     {
1191         m_eLoadState = E_FAILED;
1192         if( aEvent.State == css::frame::DispatchResultState::SUCCESS )
1193         {
1194             css::uno::Reference< css::frame::XFrame > xLastFrame; /// last target of "loadComponentFromURL()"!
1195             if ( aEvent.Result >>= xLastFrame )
1196                 m_eLoadState = E_SUCCESSFUL;
1197         }
1198     }
1199 }
1200 
1201 /*-************************************************************************************************************
1202     @interface  XEventListener
1203     @short      not implemented!
1204     @descr      We are a status listener ... and so we must be an event listener too ... But we don't need it really!
1205                 We are a temp. listener only and our lifetime isn't smaller then of our temp. used dispatcher.
1206 
1207     @seealso    method loadComponentFromURL()
1208 *//*-*************************************************************************************************************/
disposing(const css::lang::EventObject &)1209 void SAL_CALL Desktop::disposing( const css::lang::EventObject& )
1210 {
1211     SAL_WARN( "fwk.desktop", "Desktop::disposing(): Algorithm error! Normally desktop is temp. listener ... not all the time. So this method shouldn't be called." );
1212 }
1213 
1214 /*-************************************************************************************************************
1215     @interface  XInteractionHandler
1216     @short      callback for loadComponentFromURL for detected exceptions during load process
1217     @descr      In this case we must cancel loading and throw these detected exception again as result
1218                 of our own called method.
1219 
1220     @attention  a)
1221                 Normal loop in loadComponentFromURL() breaks on set member m_eLoadState during callback statusChanged().
1222                 But these interaction feature implements second way to do so! So we must look on different callbacks
1223                 for same operation ... and live with it.
1224                 b)
1225                 Search for given continuations too. If any XInteractionAbort exist ... use it to abort further operations
1226                 for currently running operation!
1227 
1228     @seealso    method loadComponentFromURL()
1229     @seealso    member m_eLoadState
1230 
1231     @param      "xRequest", request for interaction - normal a wrapped target exception from bottom services
1232     @threadsafe yes
1233 *//*-*************************************************************************************************************/
handle(const css::uno::Reference<css::task::XInteractionRequest> & xRequest)1234 void SAL_CALL Desktop::handle( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
1235 {
1236     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1237     // Register transaction and reject wrong calls.
1238     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1239 
1240     // Don't check incoming request!
1241     // If somewhere starts interaction without right parameter - he made something wrong.
1242     // loadComponentFromURL() waits for these event - otherwise it yield for ever!
1243 
1244     // get packed request and work on it first
1245     // Attention: Don't set it on internal member BEFORE interaction is finished - because
1246     // "loadComponentFromURL()" yield tills this member is changed. If we do it before
1247     // interaction finish we can't guarantee right functionality. May be we cancel load process to earlier...
1248     css::uno::Any aRequest = xRequest->getRequest();
1249 
1250     // extract continuations from request
1251     css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
1252     css::uno::Reference< css::task::XInteractionAbort >                              xAbort;
1253     css::uno::Reference< css::task::XInteractionApprove >                            xApprove;
1254     css::uno::Reference< css::document::XInteractionFilterSelect >                   xFilterSelect;
1255     bool                                                                             bAbort         = false;
1256 
1257     sal_Int32 nCount=lContinuations.getLength();
1258     for( sal_Int32 nStep=0; nStep<nCount; ++nStep )
1259     {
1260         if( ! xAbort.is() )
1261             xAbort.set( lContinuations[nStep], css::uno::UNO_QUERY );
1262 
1263         if( ! xApprove.is() )
1264             xApprove.set( lContinuations[nStep], css::uno::UNO_QUERY );
1265 
1266         if( ! xFilterSelect.is() )
1267             xFilterSelect.set( lContinuations[nStep], css::uno::UNO_QUERY );
1268     }
1269 
1270     // differ between abortable interactions (error, unknown filter...)
1271     // and other ones (ambiguous but not unknown filter...)
1272     css::task::ErrorCodeRequest          aErrorCodeRequest;
1273     if( aRequest >>= aErrorCodeRequest )
1274     {
1275         bool bWarning = ErrCode(aErrorCodeRequest.ErrCode).IsWarning();
1276         if (xApprove.is() && bWarning)
1277             xApprove->select();
1278         else
1279         if (xAbort.is())
1280         {
1281             xAbort->select();
1282             bAbort = true;
1283         }
1284     }
1285     else if( xAbort.is() )
1286     {
1287         xAbort->select();
1288         bAbort = true;
1289     }
1290 
1291     // Ok now it's time to break yield loop of loadComponentFromURL().
1292     // But only for really aborted requests!
1293     // For example warnings will be approved and we wait for any success story ...
1294     if (bAbort)
1295     {
1296         SolarMutexGuard g;
1297         m_eLoadState          = E_INTERACTION;
1298     }
1299 }
1300 
leaseNumber(const css::uno::Reference<css::uno::XInterface> & xComponent)1301 ::sal_Int32 SAL_CALL Desktop::leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent )
1302 {
1303     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1304     return m_xTitleNumberGenerator->leaseNumber (xComponent);
1305 }
1306 
releaseNumber(::sal_Int32 nNumber)1307 void SAL_CALL Desktop::releaseNumber( ::sal_Int32 nNumber )
1308 {
1309     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1310     m_xTitleNumberGenerator->releaseNumber (nNumber);
1311 }
1312 
releaseNumberForComponent(const css::uno::Reference<css::uno::XInterface> & xComponent)1313 void SAL_CALL Desktop::releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent )
1314 {
1315     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1316     m_xTitleNumberGenerator->releaseNumberForComponent (xComponent);
1317 }
1318 
getUntitledPrefix()1319 OUString SAL_CALL Desktop::getUntitledPrefix()
1320 {
1321     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1322     return m_xTitleNumberGenerator->getUntitledPrefix ();
1323 }
1324 
1325 /*-************************************************************************************************************
1326     @short      try to convert a property value
1327     @descr      This method is called from helperclass "OPropertySetHelper".
1328                 Don't use this directly!
1329                 You must try to convert the value of given PropHandle and
1330                 return results of this operation. This will be used to ask vetoable
1331                 listener. If no listener has a veto, we will change value really!
1332                 ( in method setFastPropertyValue_NoBroadcast(...) )
1333 
1334     @attention  Methods of OPropertySethelper are safed by using our shared osl mutex! (see ctor!)
1335                 So we must use different locks to make our implementation threadsafe.
1336 
1337     @seealso    class OPropertySetHelper
1338     @seealso    method setFastPropertyValue_NoBroadcast()
1339 
1340     @param      "aConvertedValue"   new converted value of property
1341     @param      "aOldValue"         old value of property
1342     @param      "nHandle"           handle of property
1343     @param      "aValue"            new value of property
1344     @return     sal_True if value will be changed, sal_FALSE otherway
1345 
1346     @onerror    IllegalArgumentException, if you call this with an invalid argument
1347     @threadsafe yes
1348 *//*-*************************************************************************************************************/
convertFastPropertyValue(css::uno::Any & aConvertedValue,css::uno::Any & aOldValue,sal_Int32 nHandle,const css::uno::Any & aValue)1349 sal_Bool SAL_CALL Desktop::convertFastPropertyValue(       css::uno::Any&   aConvertedValue ,
1350                                                            css::uno::Any&   aOldValue       ,
1351                                                            sal_Int32        nHandle         ,
1352                                                      const css::uno::Any&   aValue          )
1353 {
1354     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1355     // Register transaction and reject wrong calls.
1356     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1357 
1358     //  Initialize state with sal_False !!!
1359     //  (Handle can be invalid)
1360     bool bReturn = false;
1361 
1362     switch( nHandle )
1363     {
1364         case PropHandle::SuspendQuickstartVeto:
1365                 bReturn = PropHelper::willPropertyBeChanged(
1366                     css::uno::makeAny(m_bSuspendQuickstartVeto),
1367                     aValue,
1368                     aOldValue,
1369                     aConvertedValue);
1370                 break;
1371         case PropHandle::DispatchRecorderSupplier :
1372                 bReturn = PropHelper::willPropertyBeChanged(
1373                     css::uno::makeAny(m_xDispatchRecorderSupplier),
1374                     aValue,
1375                     aOldValue,
1376                     aConvertedValue);
1377                 break;
1378         case PropHandle::Title :
1379                 bReturn = PropHelper::willPropertyBeChanged(
1380                     css::uno::makeAny(m_sTitle),
1381                     aValue,
1382                     aOldValue,
1383                     aConvertedValue);
1384                 break;
1385     }
1386 
1387     // Return state of operation.
1388     return bReturn;
1389 }
1390 
1391 /*-************************************************************************************************************
1392     @short      set value of a transient property
1393     @descr      This method is calling from helperclass "OPropertySetHelper".
1394                 Don't use this directly!
1395                 Handle and value are valid everyway! You must set the new value only.
1396                 After this, baseclass send messages to all listener automatically.
1397 
1398     @seealso    class OPropertySetHelper
1399 
1400     @param      "nHandle"   handle of property to change
1401     @param      "aValue"    new value of property
1402     @onerror    An exception is thrown.
1403     @threadsafe yes
1404 *//*-*************************************************************************************************************/
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any & aValue)1405 void SAL_CALL Desktop::setFastPropertyValue_NoBroadcast(       sal_Int32        nHandle ,
1406                                                          const css::uno::Any&   aValue  )
1407 {
1408     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1409     // Register transaction and reject wrong calls.
1410     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1411 
1412     switch( nHandle )
1413     {
1414         case PropHandle::SuspendQuickstartVeto:    aValue >>= m_bSuspendQuickstartVeto;
1415                                                     break;
1416         case PropHandle::DispatchRecorderSupplier:    aValue >>= m_xDispatchRecorderSupplier;
1417                                                     break;
1418         case PropHandle::Title:    aValue >>= m_sTitle;
1419                                                     break;
1420     }
1421 }
1422 
1423 /*-************************************************************************************************************
1424     @short      get value of a transient property
1425     @descr      This method is calling from helperclass "OPropertySetHelper".
1426                 Don't use this directly!
1427 
1428     @attention  We don't need any mutex or lock here ... We use threadsafe container or methods here only!
1429 
1430     @seealso    class OPropertySetHelper
1431 
1432     @param      "nHandle"   handle of property to change
1433     @param      "aValue"    current value of property
1434     @threadsafe yes
1435 *//*-*************************************************************************************************************/
getFastPropertyValue(css::uno::Any & aValue,sal_Int32 nHandle) const1436 void SAL_CALL Desktop::getFastPropertyValue( css::uno::Any& aValue  ,
1437                                              sal_Int32      nHandle ) const
1438 {
1439     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1440     // Register transaction and reject wrong calls.
1441     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1442 
1443     switch( nHandle )
1444     {
1445         case PropHandle::ActiveFrame           :   aValue <<= m_aChildTaskContainer.getActive();
1446                                                     break;
1447         case PropHandle::IsPlugged           :   aValue <<= false;
1448                                                     break;
1449         case PropHandle::SuspendQuickstartVeto:    aValue <<= m_bSuspendQuickstartVeto;
1450                                                     break;
1451         case PropHandle::DispatchRecorderSupplier:    aValue <<= m_xDispatchRecorderSupplier;
1452                                                     break;
1453         case PropHandle::Title:    aValue <<= m_sTitle;
1454                                                     break;
1455     }
1456 }
1457 
getInfoHelper()1458 ::cppu::IPropertyArrayHelper& SAL_CALL Desktop::getInfoHelper()
1459 {
1460     struct Static:
1461         public rtl::StaticWithInit<cppu::OPropertyArrayHelper, Static>
1462     {
1463         cppu::OPropertyArrayHelper operator ()() {
1464             return {
1465                 {{"ActiveFrame", PropHandle::ActiveFrame,
1466                   cppu::UnoType<css::lang::XComponent>::get(),
1467                   (css::beans::PropertyAttribute::TRANSIENT
1468                    | css::beans::PropertyAttribute::READONLY)},
1469                  {"DispatchRecorderSupplier",
1470                   PropHandle::DispatchRecorderSupplier,
1471                   cppu::UnoType<css::frame::XDispatchRecorderSupplier>::get(),
1472                   css::beans::PropertyAttribute::TRANSIENT},
1473                  {"IsPlugged",
1474                   PropHandle::IsPlugged, cppu::UnoType<bool>::get(),
1475                   (css::beans::PropertyAttribute::TRANSIENT
1476                    | css::beans::PropertyAttribute::READONLY)},
1477                  {"SuspendQuickstartVeto", PropHandle::SuspendQuickstartVeto,
1478                   cppu::UnoType<bool>::get(),
1479                   css::beans::PropertyAttribute::TRANSIENT},
1480                  {"Title", PropHandle::Title, cppu::UnoType<OUString>::get(),
1481                   css::beans::PropertyAttribute::TRANSIENT}},
1482                 true};
1483         }
1484     };
1485     return Static::get();
1486 }
1487 
1488 /*-************************************************************************************************************
1489     @short      return propertysetinfo
1490     @descr      You can call this method to get information about transient properties
1491                 of this object.
1492 
1493     @attention  You must use global lock (method use static variable) ... and it must be the shareable osl mutex of it.
1494                 Because; our baseclass use this mutex to make his code threadsafe. We use our lock!
1495                 So we could have two different mutex/lock mechanism at the same object.
1496 
1497     @seealso    class OPropertySetHelper
1498     @seealso    interface XPropertySet
1499     @seealso    interface XMultiPropertySet
1500     @return     reference to object with information [XPropertySetInfo]
1501     @threadsafe yes
1502 *//*-*************************************************************************************************************/
getPropertySetInfo()1503 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL Desktop::getPropertySetInfo()
1504 {
1505     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1506     // Register transaction and reject wrong calls.
1507     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1508 
1509     // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
1510     // (Use method "getInfoHelper()".)
1511     static css::uno::Reference< css::beans::XPropertySetInfo > xInfo(
1512                     cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ) );
1513 
1514     return xInfo;
1515 }
1516 
1517 /*-************************************************************************************************************
1518     @short      return current component of current frame
1519     @descr      The desktop himself has no component. But every frame in subtree.
1520                 If somewhere call getCurrentComponent() at this class, we try to find the right frame and
1521                 then we try to become his component. It can be a VCL-component, the model or the controller
1522                 of founded frame.
1523 
1524     @attention  We don't work on internal member ... so we don't need any lock here.
1525 
1526     @seealso    method getCurrentComponent();
1527 
1528     @param      "xFrame", reference to valid frame in hierarchy. Method is not defined for invalid values.
1529                 But we don't check these. It's an IMPL-method and caller must use it right!
1530     @return     A reference to found component.
1531 
1532     @onerror    A null reference is returned.
1533     @threadsafe yes
1534 *//*-*************************************************************************************************************/
impl_getFrameComponent(const css::uno::Reference<css::frame::XFrame> & xFrame) const1535 css::uno::Reference< css::lang::XComponent > Desktop::impl_getFrameComponent( const css::uno::Reference< css::frame::XFrame >& xFrame ) const
1536 {
1537     /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1538     // Register transaction and reject wrong calls.
1539     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1540 
1541     // Set default return value, if method failed.
1542     css::uno::Reference< css::lang::XComponent > xComponent;
1543     // Does no controller exists?
1544     css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1545     if( !xController.is() )
1546     {
1547         // Controller not exist - use the VCL-component.
1548         xComponent = xFrame->getComponentWindow();
1549     }
1550     else
1551     {
1552         // Does no model exists?
1553         css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1554         if( xModel.is() )
1555         {
1556             // Model exist - use the model as component.
1557             xComponent = xModel;
1558         }
1559         else
1560         {
1561             // Model not exist - use the controller as component.
1562             xComponent = xController;
1563         }
1564     }
1565 
1566     return xComponent;
1567 }
1568 
impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList & lCalledListener,bool & bVeto)1569 void Desktop::impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList& lCalledListener,
1570                                              bool&                      bVeto          )
1571 {
1572     bVeto = false;
1573 
1574     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1575 
1576     ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1577     if ( ! pContainer )
1578         return;
1579 
1580     css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1581 
1582     ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1583     while ( aIterator.hasMoreElements() )
1584     {
1585         try
1586         {
1587             css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
1588             if ( ! xListener.is() )
1589                 continue;
1590             xListener->queryTermination( aEvent );
1591             lCalledListener.push_back(xListener);
1592         }
1593         catch( const css::frame::TerminationVetoException& )
1594         {
1595             // first veto will stop notification loop.
1596             bVeto = true;
1597             return;
1598         }
1599         catch( const css::uno::Exception& )
1600         {
1601             // clean up container.
1602             // E.g. dead remote listener objects can make trouble otherwise.
1603             // Iterator implementation allows removing objects during it's used !
1604             aIterator.remove();
1605         }
1606     }
1607 }
1608 
impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList & lCalledListener)1609 void Desktop::impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList& lCalledListener)
1610 {
1611     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1612 
1613     css::lang::EventObject                          aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1614     for (const css::uno::Reference<css::frame::XTerminateListener>& xListener : lCalledListener)
1615     {
1616         try
1617         {
1618             // Note: cancelTermination() is a new and optional interface method !
1619             css::uno::Reference< css::frame::XTerminateListener2 > xListenerGeneration2(xListener, css::uno::UNO_QUERY);
1620             if ( ! xListenerGeneration2.is() )
1621                 continue;
1622             xListenerGeneration2->cancelTermination( aEvent );
1623         }
1624         catch( const css::uno::Exception& )
1625         {}
1626     }
1627 }
1628 
impl_sendTerminateToClipboard()1629 void Desktop::impl_sendTerminateToClipboard()
1630 {
1631     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1632 
1633     ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1634     if ( ! pContainer )
1635         return;
1636 
1637     ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1638     while ( aIterator.hasMoreElements() )
1639     {
1640         try
1641         {
1642             css::uno::Reference< css::lang::XServiceInfo > xInfo( aIterator.next(), css::uno::UNO_QUERY );
1643             if ( !xInfo.is() )
1644                 continue;
1645 
1646             if ( xInfo->getImplementationName() != "com.sun.star.comp.svt.TransferableHelperTerminateListener" )
1647                 continue;
1648 
1649             css::uno::Reference< css::frame::XTerminateListener > xListener(xInfo, css::uno::UNO_QUERY);
1650             if ( ! xListener.is() )
1651                 continue;
1652 
1653             css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1654             xListener->notifyTermination( aEvent );
1655 
1656             // don't notify twice
1657             aIterator.remove();
1658         }
1659         catch( const css::uno::Exception& )
1660         {
1661             // clean up container.
1662             // E.g. dead remote listener objects can make trouble otherwise.
1663             // Iterator implementation allows removing objects during it's used !
1664             aIterator.remove();
1665         }
1666     }
1667 }
1668 
impl_sendNotifyTerminationEvent()1669 void Desktop::impl_sendNotifyTerminationEvent()
1670 {
1671     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1672 
1673     ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1674     if ( ! pContainer )
1675         return;
1676 
1677     css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1678 
1679     ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1680     while ( aIterator.hasMoreElements() )
1681     {
1682         try
1683         {
1684             css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
1685             if ( ! xListener.is() )
1686                 continue;
1687             xListener->notifyTermination( aEvent );
1688         }
1689         catch( const css::uno::Exception& )
1690         {
1691             // clean up container.
1692             // E.g. dead remote listener objects can make trouble otherwise.
1693             // Iterator implementation allows removing objects during it's used !
1694             aIterator.remove();
1695         }
1696     }
1697 }
1698 
impl_closeFrames(bool bAllowUI)1699 bool Desktop::impl_closeFrames(bool bAllowUI)
1700 {
1701     SolarMutexClearableGuard aReadLock;
1702     css::uno::Sequence< css::uno::Reference< css::frame::XFrame > > lFrames = m_aChildTaskContainer.getAllElements();
1703     aReadLock.clear();
1704 
1705     ::sal_Int32 c                = lFrames.getLength();
1706     ::sal_Int32 i                = 0;
1707     ::sal_Int32 nNonClosedFrames = 0;
1708 
1709     for( i=0; i<c; ++i )
1710     {
1711         try
1712         {
1713             css::uno::Reference< css::frame::XFrame > xFrame = lFrames[i];
1714 
1715             // XController.suspend() will show a UI ...
1716             // Use it in case it was allowed from outside only.
1717             bool                                       bSuspended = false;
1718             css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1719             if ( bAllowUI && xController.is() )
1720             {
1721                 bSuspended = xController->suspend( true );
1722                 if ( ! bSuspended )
1723                 {
1724                     ++nNonClosedFrames;
1725                     if(m_bSession)
1726                         break;
1727                     else
1728                         continue;
1729                 }
1730             }
1731 
1732             // Try to close frame (in case no UI was allowed without calling XController->suspend() before!)
1733             // But don't deliver ownership to any other one!
1734             // This method can be called again.
1735             css::uno::Reference< css::util::XCloseable > xClose( xFrame, css::uno::UNO_QUERY );
1736             if ( xClose.is() )
1737             {
1738                 try
1739                 {
1740                     xClose->close(false);
1741                 }
1742                 catch(const css::util::CloseVetoException&)
1743                 {
1744                     // Any internal process of this frame disagree with our request.
1745                     // Safe this state but don't break these loop. Other frames has to be closed!
1746                     ++nNonClosedFrames;
1747 
1748                     // Reactivate controller.
1749                     // It can happen that XController.suspend() returned true... but a registered close listener
1750                     // threw these veto exception. Then the controller has to be reactivated. Otherwise
1751                     // these document doesn't work any more.
1752                     if ( bSuspended && xController.is())
1753                         xController->suspend(false);
1754                 }
1755 
1756                 // If interface XClosable interface exists and was used...
1757                 // it's not allowed to use XComponent->dispose() also!
1758                 continue;
1759             }
1760 
1761             // XClosable not supported ?
1762             // Then we have to dispose these frame hardly.
1763             if ( xFrame.is() )
1764                 xFrame->dispose();
1765 
1766             // Don't remove these frame from our child container!
1767             // A frame do it by itself inside close()/dispose() method.
1768         }
1769         catch(const css::lang::DisposedException&)
1770         {
1771             // Dispose frames are closed frames.
1772             // So we can count it here .-)
1773         }
1774     }
1775 
1776     // reset the session
1777     m_bSession = false;
1778 
1779     return (nNonClosedFrames < 1);
1780 }
1781 
1782 }   // namespace framework
1783 
1784 namespace {
1785 
1786 struct Instance {
Instance__anoned184b700211::Instance1787     explicit Instance(
1788         css::uno::Reference<css::uno::XComponentContext> const & context):
1789         instance(new framework::Desktop(context))
1790     {
1791         instance->constructorInit();
1792     }
1793 
1794     rtl::Reference<framework::Desktop> instance;
1795 };
1796 
1797 struct InstanceInit {
operator ()__anoned184b700211::InstanceInit1798     Instance * operator() (css::uno::Reference<css::uno::XComponentContext> const& xContext) {
1799         static Instance instance(xContext);
1800         return &instance;
1801     }
1802 };
1803 
1804 struct GetSolarMutex {
operator ()__anoned184b700211::GetSolarMutex1805     comphelper::SolarMutex * operator() ()
1806     {
1807         return &Application::GetSolarMutex();
1808     }
1809 };
1810 
getInstance(css::uno::Reference<css::uno::XComponentContext> const & xContext)1811 Instance & getInstance(css::uno::Reference<css::uno::XComponentContext> const& xContext)
1812 {
1813     // tdf#114025 init with SolarMutex to avoid deadlock
1814     return *rtl_Instance<Instance,
1815                          InstanceInit,
1816                          osl::Guard<comphelper::SolarMutex>,
1817                          GetSolarMutex,
1818                          css::uno::Reference<css::uno::XComponentContext> const>
1819                 ::create(InstanceInit(), GetSolarMutex(), xContext);
1820 }
1821 
1822 }
1823 
1824 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_Desktop_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1825 com_sun_star_comp_framework_Desktop_get_implementation(
1826     css::uno::XComponentContext *context,
1827     css::uno::Sequence<css::uno::Any> const &)
1828 {
1829     return cppu::acquire(getInstance(context).instance.get());
1830 }
1831 
1832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1833