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