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