bump product version to 7.6.3.2-android
[LibreOffice.git] / framework / source / services / desktop.cxx
blob35dfcd2e21eb504e55b603dfd37223ca513da157
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <framework/desktop.hxx>
22 #include <loadenv/loadenv.hxx>
24 #include <helper/ocomponentaccess.hxx>
25 #include <helper/oframes.hxx>
26 #include <dispatch/dispatchprovider.hxx>
28 #include <dispatch/interceptionhelper.hxx>
29 #include <classes/taskcreator.hxx>
30 #include <threadhelp/transactionguard.hxx>
31 #include <properties.h>
32 #include <targets.h>
34 #include <strings.hrc>
35 #include <classes/fwkresid.hxx>
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>
50 #include <comphelper/numberedcollection.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <comphelper/lok.hxx>
53 #include <cppuhelper/supportsservice.hxx>
54 #include <utility>
55 #include <vcl/svapp.hxx>
56 #include <desktop/crashreport.hxx>
57 #include <vcl/scheduler.hxx>
58 #include <sal/log.hxx>
59 #include <comphelper/errcode.hxx>
60 #include <vcl/threadex.hxx>
61 #include <unotools/configmgr.hxx>
63 namespace framework{
65 namespace {
67 enum PropHandle {
68 ActiveFrame, DispatchRecorderSupplier, IsPlugged, SuspendQuickstartVeto,
69 Title };
73 OUString SAL_CALL Desktop::getImplementationName()
75 return "com.sun.star.comp.framework.Desktop";
78 sal_Bool SAL_CALL Desktop::supportsService(OUString const & ServiceName)
80 return cppu::supportsService(this, ServiceName);
83 css::uno::Sequence<OUString> SAL_CALL Desktop::getSupportedServiceNames()
85 return { "com.sun.star.frame.Desktop" };
88 void Desktop::constructorInit()
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 );
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 );
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 );
107 OUString sUntitledPrefix = FwkResId(STR_UNTITLED_DOCUMENT) + " ";
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 );
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!" );
119 // Enable object for real working!
120 // Otherwise all calls will be rejected ...
121 m_aTransactionManager.setWorkingMode( E_WORK );
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.
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!)
137 @seealso method DEFINE_INIT_SERVICE()
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 *//*-*************************************************************************************************************/
143 Desktop::Desktop( 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 (std::move( xContext ))
151 , m_aListenerContainer ( m_aMutex )
152 , m_eLoadState ( E_NOTSET )
153 , m_bSuspendQuickstartVeto( false )
157 /*-************************************************************************************************************
158 @short standard destructor
159 @descr This one do NOTHING! Use dispose() instead of this.
161 @seealso method dispose()
162 *//*-*************************************************************************************************************/
163 Desktop::~Desktop()
165 SAL_WARN_IF(!m_bIsShutdown, "fwk.desktop", "Desktop not terminated before being destructed");
166 SAL_WARN_IF( m_aTransactionManager.getWorkingMode()!=E_CLOSE, "fwk.desktop", "Desktop::~Desktop(): Who forgot to dispose this service?" );
169 css::uno::Any SAL_CALL Desktop::queryInterface( const css::uno::Type& _rType )
171 css::uno::Any aRet = Desktop_BASE::queryInterface( _rType );
172 if ( !aRet.hasValue() )
173 aRet = OPropertySetHelper::queryInterface( _rType );
174 return aRet;
177 css::uno::Sequence< css::uno::Type > SAL_CALL Desktop::getTypes( )
179 return comphelper::concatSequences(
180 Desktop_BASE::getTypes(),
181 ::cppu::OPropertySetHelper::getTypes()
185 sal_Bool SAL_CALL Desktop::terminate()
187 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
188 SolarMutexResettableGuard aGuard;
190 if (m_bIsTerminated)
191 return true;
193 css::uno::Reference< css::frame::XTerminateListener > xPipeTerminator = m_xPipeTerminator;
194 css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher = m_xQuickLauncher;
195 css::uno::Reference< css::frame::XTerminateListener > xSWThreadManager = m_xSWThreadManager;
196 css::uno::Reference< css::frame::XTerminateListener > xSfxTerminator = m_xSfxTerminator;
198 css::lang::EventObject aEvent ( static_cast< ::cppu::OWeakObject* >(this) );
199 bool bAskQuickStart = !m_bSuspendQuickstartVeto;
200 const bool bRestartableMainLoop = comphelper::LibreOfficeKit::isActive();
201 aGuard.clear();
203 // Allow using of any UI ... because Desktop.terminate() was designed as UI functionality in the past.
205 // Ask normal terminate listener. They could veto terminating the process.
206 Desktop::TTerminateListenerList lCalledTerminationListener;
207 if (!impl_sendQueryTerminationEvent(lCalledTerminationListener))
209 impl_sendCancelTerminationEvent(lCalledTerminationListener);
210 return false;
213 // try to close all open frames
214 if (!impl_closeFrames(!bRestartableMainLoop))
216 impl_sendCancelTerminationEvent(lCalledTerminationListener);
217 return false;
220 // Normal listener had no problem ...
221 // all frames was closed ...
222 // now it's time to ask our specialized listener.
223 // They are handled these way because they wish to hinder the office on termination
224 // but they wish also closing of all frames.
226 // Note further:
227 // We shouldn't ask quicklauncher in case it was allowed from outside only.
228 // This is special trick to "ignore existing quick starter" for debug purposes.
230 // Attention:
231 // Order of called listener is important!
232 // Some of them are harmless,-)
233 // but some can be dangerous. E.g. it would be dangerous if we close our pipe
234 // and don't terminate in real because another listener throws a veto exception .-)
238 if( bAskQuickStart && xQuickLauncher.is() )
240 xQuickLauncher->queryTermination( aEvent );
241 lCalledTerminationListener.push_back( xQuickLauncher );
244 if ( xSWThreadManager.is() )
246 xSWThreadManager->queryTermination( aEvent );
247 lCalledTerminationListener.push_back( xSWThreadManager );
250 if ( xPipeTerminator.is() )
252 xPipeTerminator->queryTermination( aEvent );
253 lCalledTerminationListener.push_back( xPipeTerminator );
256 if ( xSfxTerminator.is() )
258 xSfxTerminator->queryTermination( aEvent );
259 lCalledTerminationListener.push_back( xSfxTerminator );
262 catch(const css::frame::TerminationVetoException&)
264 impl_sendCancelTerminationEvent(lCalledTerminationListener);
265 return false;
268 aGuard.reset();
269 if (m_bIsTerminated)
270 return true;
271 m_bIsTerminated = true;
273 if (!bRestartableMainLoop)
275 CrashReporter::addKeyValue("ShutDown", OUString::boolean(true), CrashReporter::Write);
277 // The clipboard listener needs to be the first. It can create copies of the
278 // existing document which needs basically all the available infrastructure.
279 impl_sendTerminateToClipboard();
281 SolarMutexReleaser aReleaser;
282 impl_sendNotifyTerminationEvent();
284 Scheduler::ProcessEventsToIdle();
286 if( bAskQuickStart && xQuickLauncher.is() )
287 xQuickLauncher->notifyTermination( aEvent );
289 if ( xSWThreadManager.is() )
290 xSWThreadManager->notifyTermination( aEvent );
292 if ( xPipeTerminator.is() )
293 xPipeTerminator->notifyTermination( aEvent );
295 // further termination is postponed to shutdown, if LO already runs the main loop
296 if (!Application::IsInExecute())
297 shutdown();
299 else
300 m_bIsShutdown = true;
302 #ifndef IOS // or ANDROID?
303 aGuard.clear();
304 // In the iOS app, posting the ImplQuitMsg user event will be too late, it will not be handled during the
305 // lifetime of the current document, but handled for the next document opened, which thus will break horribly.
306 Application::Quit();
307 #endif
309 return true;
312 void Desktop::shutdown()
314 TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);
315 SolarMutexGuard aGuard;
317 if (m_bIsShutdown)
318 return;
319 m_bIsShutdown = true;
321 css::uno::Reference<css::frame::XTerminateListener> xSfxTerminator = m_xSfxTerminator;
322 css::lang::EventObject aEvent(static_cast<::cppu::OWeakObject* >(this));
324 // we need a copy here as the notifyTermination call might cause a removeTerminateListener call
325 std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners;
326 xComponentDllListeners.swap(m_xComponentDllListeners);
327 for (auto& xListener : xComponentDllListeners)
328 xListener->notifyTermination(aEvent);
329 xComponentDllListeners.clear();
331 // Must be really the last listener to be called.
332 // Because it shuts down the whole process asynchronous!
333 if (xSfxTerminator.is())
334 xSfxTerminator->notifyTermination(aEvent);
337 namespace
339 class QuickstartSuppressor
341 Desktop* const m_pDesktop;
342 css::uno::Reference< css::frame::XTerminateListener > m_xQuickLauncher;
343 public:
344 QuickstartSuppressor(Desktop* const pDesktop, css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher)
345 : m_pDesktop(pDesktop)
346 , m_xQuickLauncher(std::move(xQuickLauncher))
348 SAL_INFO("fwk.desktop", "temporary removing Quickstarter");
349 if(m_xQuickLauncher.is())
350 m_pDesktop->removeTerminateListener(m_xQuickLauncher);
352 ~QuickstartSuppressor()
354 SAL_INFO("fwk.desktop", "readding Quickstarter");
355 if(m_xQuickLauncher.is())
356 m_pDesktop->addTerminateListener(m_xQuickLauncher);
361 bool Desktop::terminateQuickstarterToo()
363 QuickstartSuppressor aQuickstartSuppressor(this, m_xQuickLauncher);
364 m_bSession = true;
365 return terminate();
368 void SAL_CALL Desktop::addTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
370 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
372 css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
373 if ( xInfo.is() )
375 OUString sImplementationName = xInfo->getImplementationName();
377 SolarMutexGuard g;
379 if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
381 m_xSfxTerminator = xListener;
382 return;
384 if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
386 m_xPipeTerminator = xListener;
387 return;
389 if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
391 m_xQuickLauncher = xListener;
392 return;
394 if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
396 m_xSWThreadManager = xListener;
397 return;
399 else if ( sImplementationName == "com.sun.star.comp.ComponentDLLListener" )
401 m_xComponentDllListeners.push_back(xListener);
402 return;
406 // No lock required... container is threadsafe by itself.
407 m_aListenerContainer.addInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
410 void SAL_CALL Desktop::removeTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
412 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
414 css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
415 if ( xInfo.is() )
417 OUString sImplementationName = xInfo->getImplementationName();
419 SolarMutexGuard g;
421 if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
423 m_xSfxTerminator.clear();
424 return;
427 if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
429 m_xPipeTerminator.clear();
430 return;
433 if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
435 m_xQuickLauncher.clear();
436 return;
439 if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
441 m_xSWThreadManager.clear();
442 return;
444 else if (sImplementationName == "com.sun.star.comp.ComponentDLLListener")
446 m_xComponentDllListeners.erase(
447 std::remove(m_xComponentDllListeners.begin(), m_xComponentDllListeners.end(), xListener),
448 m_xComponentDllListeners.end());
449 return;
453 // No lock required ... container is threadsafe by itself.
454 m_aListenerContainer.removeInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
457 /*-************************************************************************************************************
458 @interface XDesktop
459 @short get access to create enumerations of all current components
460 @descr You will be the owner of the returned object and must delete it if you don't use it again.
462 @seealso class TasksAccess
463 @seealso class TasksEnumeration
464 @return A reference to an XEnumerationAccess-object.
466 @onerror We return a null-reference.
467 @threadsafe yes
468 *//*-*************************************************************************************************************/
469 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getComponents()
471 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
472 // Register transaction and reject wrong calls.
473 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
475 // We use a helper class OComponentAccess to have access on all child components.
476 // Create it on demand and return it as a reference.
477 return new OComponentAccess( this );
480 /*-************************************************************************************************************
481 @interface XDesktop
482 @short return the current active component
483 @descr The most current component is the window, model or the controller of the current active frame.
485 @seealso method getCurrentFrame()
486 @seealso method impl_getFrameComponent()
487 @return A reference to the component.
489 @onerror We return a null-reference.
490 @threadsafe yes
491 *//*-*************************************************************************************************************/
492 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::getCurrentComponent()
494 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
495 // Register transaction and reject wrong calls.
496 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
498 // Set return value if method failed.
499 css::uno::Reference< css::lang::XComponent > xComponent;
501 // Get reference to current frame ...
502 // ... get component of this frame ... (It can be the window, the model or the controller.)
503 // ... and return the result.
504 css::uno::Reference< css::frame::XFrame > xCurrentFrame = getCurrentFrame();
505 if( xCurrentFrame.is() )
507 xComponent = impl_getFrameComponent( xCurrentFrame );
509 return xComponent;
512 /*-************************************************************************************************************
513 @interface XDesktop
514 @short return the current active frame in hierarchy
515 @descr There can be more than one different active paths in our frame hierarchy. But only one of them
516 could be the most active frame (normal he has the focus).
517 Don't mix it with getActiveFrame()! That will return our current active frame, which must be
518 a direct child of us and should be a part(!) of an active path.
520 @seealso method getActiveFrame()
521 @return A valid reference, if there is an active frame.
522 A null reference , otherwise.
524 @onerror We return a null reference.
525 @threadsafe yes
526 *//*-*************************************************************************************************************/
527 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getCurrentFrame()
529 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
530 // Register transaction and reject wrong calls.
531 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
533 // Start search with our direct active frame (if it exist!).
534 // Search on his children for other active frames too.
535 // Stop if no one could be found and return last of found ones.
536 css::uno::Reference< css::frame::XFramesSupplier > xLast( getActiveFrame(), css::uno::UNO_QUERY );
537 if( xLast.is() )
539 css::uno::Reference< css::frame::XFramesSupplier > xNext( xLast->getActiveFrame(), css::uno::UNO_QUERY );
540 while( xNext.is() )
542 xLast = xNext;
543 xNext.set( xNext->getActiveFrame(), css::uno::UNO_QUERY );
546 return xLast;
549 /*-************************************************************************************************************
550 @interface XComponentLoader
551 @short try to load given URL into a task
552 @descr You can give us some information about the content, which you will load into a frame.
553 We search or create this target for you, make a type detection of given URL and try to load it.
554 As result of this operation we return the new created component or nothing, if loading failed.
555 @param "sURL" , URL, which represent the content
556 @param "sTargetFrameName" , name of target frame or special value like "_self", "_blank" ...
557 @param "nSearchFlags" , optional arguments for frame search, if target isn't a special one
558 @param "lArguments" , optional arguments for loading
559 @return A valid component reference, if loading was successful.
560 A null reference otherwise.
562 @onerror We return a null reference.
563 @threadsafe yes
564 *//*-*************************************************************************************************************/
565 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::loadComponentFromURL( const OUString& sURL ,
566 const OUString& sTargetFrameName,
567 sal_Int32 nSearchFlags ,
568 const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
570 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
571 // Register transaction and reject wrong calls.
572 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
573 SAL_INFO( "fwk.desktop", "loadComponentFromURL" );
575 css::uno::Reference< css::frame::XComponentLoader > xThis(this);
577 utl::MediaDescriptor aDescriptor(lArguments);
578 bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
580 if (bOnMainThread)
582 // Make sure that we own the solar mutex, otherwise later
583 // vcl::SolarThreadExecutor::execute() will release the solar mutex, even if it's owned by
584 // another thread, leading to an std::abort() at the end.
585 SolarMutexGuard g;
587 return vcl::solarthread::syncExecute(std::bind(&LoadEnv::loadComponentFromURL, xThis,
588 m_xContext, sURL, sTargetFrameName,
589 nSearchFlags, lArguments));
591 else
593 return LoadEnv::loadComponentFromURL(xThis, m_xContext, sURL, sTargetFrameName,
594 nSearchFlags, lArguments);
598 /*-************************************************************************************************************
599 @interface XTasksSupplier
600 @short get access to create enumerations of our taskchildren
601 @descr Direct children of desktop are tasks every time.
602 Call these method to could create enumerations of it.
604 But; Don't forget - you will be the owner of returned object and must release it!
605 We use a helper class to implement the access interface. They hold a weakreference to us.
606 It can be, that the desktop is dead - but not your tasksaccess-object! Then they will do nothing!
607 You can't create enumerations then.
609 @attention Normally we don't need any lock here. We don't work on internal member!
611 @seealso class TasksAccess
612 @return A reference to an accessobject, which can create enumerations of our childtasks.
614 @onerror A null reference is returned.
615 @threadsafe yes
616 *//*-*************************************************************************************************************/
617 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getTasks()
619 SAL_INFO("fwk.desktop", "Desktop::getTasks(): Use of obsolete interface XTaskSupplier");
620 return nullptr;
623 /*-************************************************************************************************************
624 @interface XTasksSupplier
625 @short return current active task of our direct children
626 @descr Desktop children are tasks only ! If we have an active path from desktop
627 as top to any frame on bottom, we must have an active direct child. His reference is returned here.
629 @attention a) Do not confuse it with getCurrentFrame()! The current frame don't must one of our direct children.
630 It can be every frame in subtree and must have the focus (Is the last one of an active path!).
631 b) We don't need any lock here. Our container is threadsafe himself and live, if we live!
633 @seealso method getCurrentFrame()
634 @return A reference to our current active taskchild.
636 @onerror A null reference is returned.
637 @threadsafe yes
638 *//*-*************************************************************************************************************/
639 css::uno::Reference< css::frame::XTask > SAL_CALL Desktop::getActiveTask()
641 SAL_INFO("fwk.desktop", "Desktop::getActiveTask(): Use of obsolete interface XTaskSupplier");
642 return nullptr;
645 /*-************************************************************************************************************
646 @interface XDispatchProvider
647 @short search a dispatcher for given URL
648 @descr We use a helper implementation (class DispatchProvider) to do so.
649 So we don't must implement this algorithm twice!
651 @attention We don't need any lock here. Our helper is threadsafe himself and live, if we live!
653 @seealso class DispatchProvider
655 @param "aURL" , URL to dispatch
656 @param "sTargetFrameName" , name of target frame, who should dispatch these URL
657 @param "nSearchFlags" , flags to regulate the search
658 @param "lQueries" , list of queryDispatch() calls!
659 @return A reference or list of founded dispatch objects for these URL.
661 @onerror A null reference is returned.
662 @threadsafe yes
663 *//*-*************************************************************************************************************/
664 css::uno::Reference< css::frame::XDispatch > SAL_CALL Desktop::queryDispatch( const css::util::URL& aURL ,
665 const OUString& sTargetFrameName ,
666 sal_Int32 nSearchFlags )
668 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
669 // Register transaction and reject wrong calls.
670 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
672 // Remove uno and cmd protocol part as we want to support both of them. We store only the command part
673 // in our hash map. All other protocols are stored with the protocol part.
674 OUString aCommand( aURL.Main );
675 if ( aURL.Protocol.equalsIgnoreAsciiCase(".uno:") )
676 aCommand = aURL.Path;
678 if (!m_xCommandOptions && !utl::ConfigManager::IsFuzzing())
679 m_xCommandOptions.reset(new SvtCommandOptions);
681 // Make std::unordered_map lookup if the current URL is in the disabled list
682 if (m_xCommandOptions && m_xCommandOptions->LookupDisabled(aCommand))
683 return css::uno::Reference< css::frame::XDispatch >();
684 else
686 // We use a helper to support these interface and an interceptor mechanism.
687 // Our helper is threadsafe by himself!
688 return m_xDispatchHelper->queryDispatch( aURL, sTargetFrameName, nSearchFlags );
692 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL Desktop::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lQueries )
694 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
695 // Register transaction and reject wrong calls.
696 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
698 return m_xDispatchHelper->queryDispatches( lQueries );
701 /*-************************************************************************************************************
702 @interface XDispatchProviderInterception
703 @short supports registration/deregistration of interception objects, which
704 are interested on special dispatches.
706 @descr It's really provided by an internal helper, which is used inside the dispatch API too.
707 @param xInterceptor
708 the interceptor object, which wishes to be (de)registered.
710 @threadsafe yes
711 *//*-*************************************************************************************************************/
712 void SAL_CALL Desktop::registerDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
714 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
716 css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
717 xInterceptionHelper->registerDispatchProviderInterceptor( xInterceptor );
720 void SAL_CALL Desktop::releaseDispatchProviderInterceptor ( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
722 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
724 css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
725 xInterceptionHelper->releaseDispatchProviderInterceptor( xInterceptor );
728 /*-************************************************************************************************************
729 @interface XFramesSupplier
730 @short return access to append or remove children on desktop
731 @descr We don't implement these interface directly. We use a helper class to do this.
732 If you wish to add or delete children to/from the container, call these method to get
733 a reference to the helper.
735 @attention Helper is threadsafe himself. So we don't need any lock here.
737 @seealso class OFrames
738 @return A reference to the helper.
740 @onerror A null reference is returned.
741 @threadsafe yes
742 *//*-*************************************************************************************************************/
743 css::uno::Reference< css::frame::XFrames > SAL_CALL Desktop::getFrames()
745 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
746 // Register transaction and reject wrong calls.
747 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
749 return m_xFramesHelper;
752 /*-************************************************************************************************************
753 @interface XFramesSupplier
754 @short set/get the current active child frame
755 @descr It must be a task. Direct children of desktop are tasks only! No frames are accepted.
756 We don't save this information directly in this class. We use our container-helper
757 to do that.
759 @attention Helper is threadsafe himself. So we don't need any lock here.
761 @seealso class OFrameContainer
763 @param "xFrame", new active frame (must be valid!)
764 @return A reference to our current active childtask, if anyone exist.
766 @onerror A null reference is returned.
767 @threadsafe yes
768 *//*-*************************************************************************************************************/
769 void SAL_CALL Desktop::setActiveFrame( const css::uno::Reference< css::frame::XFrame >& xFrame )
771 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
772 // Register transaction and reject wrong calls.
773 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
775 // Get old active frame first.
776 // If nothing will change - do nothing!
777 // Otherwise set new active frame ...
778 // and deactivate last frame.
779 // It's necessary for our FrameActionEvent listener on a frame!
780 css::uno::Reference< css::frame::XFrame > xLastActiveChild = m_aChildTaskContainer.getActive();
781 if( xLastActiveChild != xFrame )
783 m_aChildTaskContainer.setActive( xFrame );
784 if( xLastActiveChild.is() )
786 xLastActiveChild->deactivate();
791 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getActiveFrame()
793 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
794 // Register transaction and reject wrong calls.
795 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
797 return m_aChildTaskContainer.getActive();
801 @interface XFrame
802 @short non implemented methods!
803 @descr Some method make no sense for our desktop! He has no window or parent or ...
804 So we should implement it empty and warn programmer, if he use it!
806 void SAL_CALL Desktop::initialize( const css::uno::Reference< css::awt::XWindow >& )
810 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getContainerWindow()
812 return css::uno::Reference< css::awt::XWindow >();
815 void SAL_CALL Desktop::setCreator( const css::uno::Reference< css::frame::XFramesSupplier >& /*xCreator*/ )
819 css::uno::Reference< css::frame::XFramesSupplier > SAL_CALL Desktop::getCreator()
821 return css::uno::Reference< css::frame::XFramesSupplier >();
824 OUString SAL_CALL Desktop::getName()
826 SolarMutexGuard g;
827 return m_sName;
830 void SAL_CALL Desktop::setName( const OUString& sName )
832 SolarMutexGuard g;
833 m_sName = sName;
836 sal_Bool SAL_CALL Desktop::isTop()
838 return true;
841 void SAL_CALL Desktop::activate()
843 // Desktop is active always... but sometimes our frames try to activate
844 // the complete path from bottom to top... And our desktop is the topest frame :-(
845 // So - please don't show any assertions here. Do nothing!
848 void SAL_CALL Desktop::deactivate()
850 // Desktop is active always... but sometimes our frames try to deactivate
851 // the complete path from bottom to top... And our desktop is the topest frame :-(
852 // So - please don't show any assertions here. Do nothing!
855 sal_Bool SAL_CALL Desktop::isActive()
857 return true;
860 sal_Bool SAL_CALL Desktop::setComponent( const css::uno::Reference< css::awt::XWindow >& /*xComponentWindow*/ ,
861 const css::uno::Reference< css::frame::XController >& /*xController*/ )
863 return false;
866 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getComponentWindow()
868 return css::uno::Reference< css::awt::XWindow >();
871 css::uno::Reference< css::frame::XController > SAL_CALL Desktop::getController()
873 return css::uno::Reference< css::frame::XController >();
876 void SAL_CALL Desktop::contextChanged()
880 void SAL_CALL Desktop::addFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
884 // css::frame::XFrame
885 void SAL_CALL Desktop::removeFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
889 /*-************************************************************************************************************
890 @interface XFrame
891 @short try to find a frame with special parameters
892 @descr This method searches for a frame with the specified name.
893 Frames may contain other frames (e.g. a frameset) and may
894 be contained in other frames. This hierarchy is searched by
895 this method.
896 First some special names are taken into account, i.e. "",
897 "_self", "_top", "_parent" etc. The FrameSearchFlags are ignored
898 when comparing these names with aTargetFrameName, further steps are
899 controlled by the FrameSearchFlags. If allowed, the name of the frame
900 itself is compared with the desired one, then ( again if allowed )
901 the method findFrame is called for all children of the frame.
902 If no Frame with the given name is found until the top frames container,
903 a new top Frame is created, if this is allowed by a special
904 FrameSearchFlag. The new Frame also gets the desired name.
905 We use a helper to get right search direction and react in a right manner.
907 @seealso class TargetFinder
909 @param "sTargetFrameName" , name of searched frame
910 @param "nSearchFlags" , flags to regulate search
911 @return A reference to an existing frame in hierarchy, if it exist.
913 @onerror A null reference is returned.
914 @threadsafe yes
915 *//*-*************************************************************************************************************/
916 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::findFrame( const OUString& sTargetFrameName ,
917 sal_Int32 nSearchFlags )
919 css::uno::Reference< css::frame::XFrame > xTarget;
921 // 0) Ignore wrong parameter!
922 // We don't support search for following special targets.
923 // If we reject these requests, we must not check for such names
924 // in following code again and again. If we do not, so wrong
925 // search results can occur!
927 if (
928 (sTargetFrameName==SPECIALTARGET_DEFAULT ) || // valid for dispatches - not for findFrame()!
929 (sTargetFrameName==SPECIALTARGET_PARENT ) || // we have no parent by definition
930 (sTargetFrameName==SPECIALTARGET_BEAMER ) // beamer frames are allowed as child of tasks only -
931 // and they exist more than ones. We have no idea which our sub tasks is the right one
934 return nullptr;
937 // I) check for special defined targets first which must be handled exclusive.
938 // force using of "if() else if() ..."
940 // I.I) "_blank"
941 // create a new task as child of this desktop instance
942 // Note: Used helper TaskCreator use us automatically ...
944 if ( sTargetFrameName==SPECIALTARGET_BLANK )
946 TaskCreator aCreator( m_xContext );
947 xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
950 // I.II) "_top"
951 // We are top by definition
953 else if ( sTargetFrameName==SPECIALTARGET_TOP )
955 xTarget = this;
958 // I.III) "_self", ""
959 // This mean this "frame" in every case.
961 else if (
962 ( sTargetFrameName==SPECIALTARGET_SELF ) ||
963 ( sTargetFrameName.isEmpty() )
966 xTarget = this;
969 else
972 // II) otherwise use optional given search flags
973 // force using of combinations of such flags. means no "else" part of use if() statements.
974 // But we ust break further searches if target was already found.
975 // Order of using flags is fix: SELF - CHILDREN - SIBLINGS - PARENT
976 // TASK and CREATE are handled special.
977 // But note: Such flags are not valid for the desktop - especially SIBLINGS or PARENT.
979 // II.I) SELF
980 // Check for right name. If it's the searched one return ourself - otherwise
981 // ignore this flag.
983 if (
984 (nSearchFlags & css::frame::FrameSearchFlag::SELF) &&
985 (m_sName == sTargetFrameName)
988 xTarget = this;
991 // II.II) TASKS
992 // This is a special flag. Normally it regulate search inside tasks and forbid access to parent trees.
993 // But the desktop exists outside such task trees. They are our sub trees. So the desktop implement
994 // a special feature: We use it to start search on our direct children only. That means we suppress
995 // search on ALL child frames. May that can be useful to get access on opened document tasks
996 // only without filter out all non really required sub frames ...
997 // Used helper method on our container doesn't create any frame - it's a search only.
999 if (
1000 ( ! xTarget.is() ) &&
1001 (nSearchFlags & css::frame::FrameSearchFlag::TASKS)
1004 xTarget = m_aChildTaskContainer.searchOnDirectChildrens(sTargetFrameName);
1007 // II.III) CHILDREN
1008 // Search on all children for the given target name.
1009 // An empty name value can't occur here - because it must be already handled as "_self"
1010 // before. Used helper function of container doesn't create any frame.
1011 // It makes a deep search only.
1013 if (
1014 ( ! xTarget.is() ) &&
1015 (nSearchFlags & css::frame::FrameSearchFlag::CHILDREN)
1018 xTarget = m_aChildTaskContainer.searchOnAllChildrens(sTargetFrameName);
1021 // II.IV) CREATE
1022 // If we haven't found any valid target frame by using normal flags - but user allowed us to create
1023 // a new one ... we should do that. Used TaskCreator use us automatically as parent!
1025 if (
1026 ( ! xTarget.is() ) &&
1027 (nSearchFlags & css::frame::FrameSearchFlag::CREATE)
1030 TaskCreator aCreator( m_xContext );
1031 xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
1035 return xTarget;
1038 void SAL_CALL Desktop::disposing()
1040 // Safe impossible cases
1041 // It's a programming error if dispose is called before terminate!
1043 // But if you just ignore the assertion (which happens in unit
1044 // tests for instance in sc/qa/unit) nothing bad happens.
1045 assert(m_bIsShutdown && "Desktop disposed before terminating it");
1048 SolarMutexGuard aWriteLock;
1051 TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);
1054 // Disable this instance for further work.
1055 // This will wait for all current running transactions ...
1056 // and reject all new incoming requests!
1057 m_aTransactionManager.setWorkingMode(E_BEFORECLOSE);
1060 // Following lines of code can be called outside a synchronized block ...
1061 // Because our transaction manager will block all new requests to this object.
1062 // So nobody can use us any longer.
1063 // Exception: Only removing of listener will work ... and this code can't be dangerous.
1065 // First we have to kill all listener connections.
1066 // They might rely on our member and can hinder us on releasing them.
1067 css::uno::Reference< css::uno::XInterface > xThis ( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
1068 css::lang::EventObject aEvent( xThis );
1069 m_aListenerContainer.disposeAndClear( aEvent );
1071 // Clear our child task container and forget all task references hardly.
1072 // Normally all open document was already closed by our terminate() function before ...
1073 // New opened frames will have a problem now .-)
1074 m_aChildTaskContainer.clear();
1076 // Dispose our helper too.
1077 css::uno::Reference< css::lang::XEventListener > xFramesHelper( m_xFramesHelper, css::uno::UNO_QUERY );
1078 if( xFramesHelper.is() )
1079 xFramesHelper->disposing( aEvent );
1081 // At least clean up other member references.
1082 m_xDispatchHelper.clear();
1083 m_xFramesHelper.clear();
1084 m_xContext.clear();
1086 m_xPipeTerminator.clear();
1087 m_xQuickLauncher.clear();
1088 m_xSWThreadManager.clear();
1090 // we need a copy because the disposing might call the removeEventListener method
1091 std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners;
1092 xComponentDllListeners.swap(m_xComponentDllListeners);
1093 for (auto& xListener: xComponentDllListeners)
1095 xListener->disposing(aEvent);
1097 xComponentDllListeners.clear();
1098 m_xSfxTerminator.clear();
1099 m_xCommandOptions.reset();
1101 // From this point nothing will work further on this object ...
1102 // excepting our dtor() .-)
1103 m_aTransactionManager.setWorkingMode( E_CLOSE );
1107 @interface XComponent
1108 @short add/remove listener for dispose events
1109 @descr Add an event listener to this object, if you wish to get information
1110 about our dying!
1111 You must release this listener reference during your own disposing() method.
1113 @attention Our container is threadsafe himself. So we don't need any lock here.
1114 @param "xListener", reference to valid listener. We don't accept invalid values!
1115 @threadsafe yes
1117 void SAL_CALL Desktop::addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1119 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1120 // Safe impossible cases
1121 // Method not defined for all incoming parameter.
1122 SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::addEventListener(): Invalid parameter detected!" );
1123 // Register transaction and reject wrong calls.
1124 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1126 m_aListenerContainer.addInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1129 void SAL_CALL Desktop::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1131 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1132 // Safe impossible cases
1133 // Method not defined for all incoming parameter.
1134 SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::removeEventListener(): Invalid parameter detected!" );
1135 // Register transaction and reject wrong calls.
1136 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
1138 m_aListenerContainer.removeInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1141 /*-************************************************************************************************************
1142 @interface XDispatchResultListener
1143 @short callback for dispatches
1144 @descr To support our method "loadComponentFromURL()" we are listener on temp. created dispatcher.
1145 They call us back in this method "statusChanged()". As source of given state event, they give us a
1146 reference to the target frame, in which dispatch was loaded! So we can use it to return his component
1147 to caller! If no target exist ... ??!!
1149 @seealso method loadComponentFromURL()
1151 @param "aEvent", state event which (hopefully) valid information
1152 @threadsafe yes
1153 *//*-*************************************************************************************************************/
1154 void SAL_CALL Desktop::dispatchFinished( const css::frame::DispatchResultEvent& aEvent )
1156 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1157 // Register transaction and reject wrong calls.
1158 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1160 SolarMutexGuard g;
1161 if( m_eLoadState != E_INTERACTION )
1163 m_eLoadState = E_FAILED;
1164 if( aEvent.State == css::frame::DispatchResultState::SUCCESS )
1166 css::uno::Reference< css::frame::XFrame > xLastFrame; /// last target of "loadComponentFromURL()"!
1167 if ( aEvent.Result >>= xLastFrame )
1168 m_eLoadState = E_SUCCESSFUL;
1173 /*-************************************************************************************************************
1174 @interface XEventListener
1175 @short not implemented!
1176 @descr We are a status listener ... and so we must be an event listener too ... But we don't need it really!
1177 We are a temp. listener only and our lifetime isn't smaller then of our temp. used dispatcher.
1179 @seealso method loadComponentFromURL()
1180 *//*-*************************************************************************************************************/
1181 void SAL_CALL Desktop::disposing( const css::lang::EventObject& )
1183 SAL_WARN( "fwk.desktop", "Desktop::disposing(): Algorithm error! Normally desktop is temp. listener ... not all the time. So this method shouldn't be called." );
1186 /*-************************************************************************************************************
1187 @interface XInteractionHandler
1188 @short callback for loadComponentFromURL for detected exceptions during load process
1189 @descr In this case we must cancel loading and throw these detected exception again as result
1190 of our own called method.
1192 @attention a)
1193 Normal loop in loadComponentFromURL() breaks on set member m_eLoadState during callback statusChanged().
1194 But these interaction feature implements second way to do so! So we must look on different callbacks
1195 for same operation ... and live with it.
1197 Search for given continuations too. If any XInteractionAbort exist ... use it to abort further operations
1198 for currently running operation!
1200 @seealso method loadComponentFromURL()
1201 @seealso member m_eLoadState
1203 @param "xRequest", request for interaction - normal a wrapped target exception from bottom services
1204 @threadsafe yes
1205 *//*-*************************************************************************************************************/
1206 void SAL_CALL Desktop::handle( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
1208 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1209 // Register transaction and reject wrong calls.
1210 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1212 // Don't check incoming request!
1213 // If somewhere starts interaction without right parameter - he made something wrong.
1214 // loadComponentFromURL() waits for these event - otherwise it yield for ever!
1216 // get packed request and work on it first
1217 // Attention: Don't set it on internal member BEFORE interaction is finished - because
1218 // "loadComponentFromURL()" yield tills this member is changed. If we do it before
1219 // interaction finish we can't guarantee right functionality. May be we cancel load process to earlier...
1220 css::uno::Any aRequest = xRequest->getRequest();
1222 // extract continuations from request
1223 css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
1224 css::uno::Reference< css::task::XInteractionAbort > xAbort;
1225 css::uno::Reference< css::task::XInteractionApprove > xApprove;
1226 css::uno::Reference< css::document::XInteractionFilterSelect > xFilterSelect;
1227 bool bAbort = false;
1229 sal_Int32 nCount=lContinuations.getLength();
1230 for( sal_Int32 nStep=0; nStep<nCount; ++nStep )
1232 if( ! xAbort.is() )
1233 xAbort.set( lContinuations[nStep], css::uno::UNO_QUERY );
1235 if( ! xApprove.is() )
1236 xApprove.set( lContinuations[nStep], css::uno::UNO_QUERY );
1238 if( ! xFilterSelect.is() )
1239 xFilterSelect.set( lContinuations[nStep], css::uno::UNO_QUERY );
1242 // differ between abortable interactions (error, unknown filter...)
1243 // and other ones (ambiguous but not unknown filter...)
1244 css::task::ErrorCodeRequest aErrorCodeRequest;
1245 if( aRequest >>= aErrorCodeRequest )
1247 bool bWarning = ErrCode(aErrorCodeRequest.ErrCode).IsWarning();
1248 if (xApprove.is() && bWarning)
1249 xApprove->select();
1250 else
1251 if (xAbort.is())
1253 xAbort->select();
1254 bAbort = true;
1257 else if( xAbort.is() )
1259 xAbort->select();
1260 bAbort = true;
1263 // Ok now it's time to break yield loop of loadComponentFromURL().
1264 // But only for really aborted requests!
1265 // For example warnings will be approved and we wait for any success story ...
1266 if (bAbort)
1268 SolarMutexGuard g;
1269 m_eLoadState = E_INTERACTION;
1273 ::sal_Int32 SAL_CALL Desktop::leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent )
1275 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1276 return m_xTitleNumberGenerator->leaseNumber (xComponent);
1279 void SAL_CALL Desktop::releaseNumber( ::sal_Int32 nNumber )
1281 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1282 m_xTitleNumberGenerator->releaseNumber (nNumber);
1285 void SAL_CALL Desktop::releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent )
1287 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1288 m_xTitleNumberGenerator->releaseNumberForComponent (xComponent);
1291 OUString SAL_CALL Desktop::getUntitledPrefix()
1293 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1294 return m_xTitleNumberGenerator->getUntitledPrefix ();
1297 /*-************************************************************************************************************
1298 @short try to convert a property value
1299 @descr This method is called from helperclass "OPropertySetHelper".
1300 Don't use this directly!
1301 You must try to convert the value of given PropHandle and
1302 return results of this operation. This will be used to ask vetoable
1303 listener. If no listener has a veto, we will change value really!
1304 ( in method setFastPropertyValue_NoBroadcast(...) )
1306 @attention Methods of OPropertySethelper are safed by using our shared osl mutex! (see ctor!)
1307 So we must use different locks to make our implementation threadsafe.
1309 @seealso class OPropertySetHelper
1310 @seealso method setFastPropertyValue_NoBroadcast()
1312 @param "aConvertedValue" new converted value of property
1313 @param "aOldValue" old value of property
1314 @param "nHandle" handle of property
1315 @param "aValue" new value of property
1316 @return sal_True if value will be changed, sal_FALSE otherway
1318 @onerror IllegalArgumentException, if you call this with an invalid argument
1319 @threadsafe yes
1320 *//*-*************************************************************************************************************/
1321 sal_Bool SAL_CALL Desktop::convertFastPropertyValue( css::uno::Any& aConvertedValue ,
1322 css::uno::Any& aOldValue ,
1323 sal_Int32 nHandle ,
1324 const css::uno::Any& aValue )
1326 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1327 // Register transaction and reject wrong calls.
1328 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1330 // Initialize state with sal_False !!!
1331 // (Handle can be invalid)
1332 bool bReturn = false;
1334 switch( nHandle )
1336 case PropHandle::SuspendQuickstartVeto:
1337 bReturn = PropHelper::willPropertyBeChanged(
1338 css::uno::Any(m_bSuspendQuickstartVeto),
1339 aValue,
1340 aOldValue,
1341 aConvertedValue);
1342 break;
1343 case PropHandle::DispatchRecorderSupplier :
1344 bReturn = PropHelper::willPropertyBeChanged(
1345 css::uno::Any(m_xDispatchRecorderSupplier),
1346 aValue,
1347 aOldValue,
1348 aConvertedValue);
1349 break;
1350 case PropHandle::Title :
1351 bReturn = PropHelper::willPropertyBeChanged(
1352 css::uno::Any(m_sTitle),
1353 aValue,
1354 aOldValue,
1355 aConvertedValue);
1356 break;
1359 // Return state of operation.
1360 return bReturn;
1363 /*-************************************************************************************************************
1364 @short set value of a transient property
1365 @descr This method is calling from helperclass "OPropertySetHelper".
1366 Don't use this directly!
1367 Handle and value are valid everyway! You must set the new value only.
1368 After this, baseclass send messages to all listener automatically.
1370 @seealso class OPropertySetHelper
1372 @param "nHandle" handle of property to change
1373 @param "aValue" new value of property
1374 @onerror An exception is thrown.
1375 @threadsafe yes
1376 *//*-*************************************************************************************************************/
1377 void SAL_CALL Desktop::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle ,
1378 const css::uno::Any& aValue )
1380 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1381 // Register transaction and reject wrong calls.
1382 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1384 switch( nHandle )
1386 case PropHandle::SuspendQuickstartVeto: aValue >>= m_bSuspendQuickstartVeto;
1387 break;
1388 case PropHandle::DispatchRecorderSupplier: aValue >>= m_xDispatchRecorderSupplier;
1389 break;
1390 case PropHandle::Title: aValue >>= m_sTitle;
1391 break;
1395 /*-************************************************************************************************************
1396 @short get value of a transient property
1397 @descr This method is calling from helperclass "OPropertySetHelper".
1398 Don't use this directly!
1400 @attention We don't need any mutex or lock here ... We use threadsafe container or methods here only!
1402 @seealso class OPropertySetHelper
1404 @param "nHandle" handle of property to change
1405 @param "aValue" current value of property
1406 @threadsafe yes
1407 *//*-*************************************************************************************************************/
1408 void SAL_CALL Desktop::getFastPropertyValue( css::uno::Any& aValue ,
1409 sal_Int32 nHandle ) const
1411 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1412 // Register transaction and reject wrong calls.
1413 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1415 switch( nHandle )
1417 case PropHandle::ActiveFrame : aValue <<= m_aChildTaskContainer.getActive();
1418 break;
1419 case PropHandle::IsPlugged : aValue <<= false;
1420 break;
1421 case PropHandle::SuspendQuickstartVeto: aValue <<= m_bSuspendQuickstartVeto;
1422 break;
1423 case PropHandle::DispatchRecorderSupplier: aValue <<= m_xDispatchRecorderSupplier;
1424 break;
1425 case PropHandle::Title: aValue <<= m_sTitle;
1426 break;
1430 ::cppu::IPropertyArrayHelper& SAL_CALL Desktop::getInfoHelper()
1432 static cppu::OPropertyArrayHelper HELPER =
1433 [] () {
1434 return cppu::OPropertyArrayHelper {
1435 {{"ActiveFrame", PropHandle::ActiveFrame,
1436 cppu::UnoType<css::lang::XComponent>::get(),
1437 (css::beans::PropertyAttribute::TRANSIENT
1438 | css::beans::PropertyAttribute::READONLY)},
1439 {"DispatchRecorderSupplier",
1440 PropHandle::DispatchRecorderSupplier,
1441 cppu::UnoType<css::frame::XDispatchRecorderSupplier>::get(),
1442 css::beans::PropertyAttribute::TRANSIENT},
1443 {"IsPlugged",
1444 PropHandle::IsPlugged, cppu::UnoType<bool>::get(),
1445 (css::beans::PropertyAttribute::TRANSIENT
1446 | css::beans::PropertyAttribute::READONLY)},
1447 {"SuspendQuickstartVeto", PropHandle::SuspendQuickstartVeto,
1448 cppu::UnoType<bool>::get(),
1449 css::beans::PropertyAttribute::TRANSIENT},
1450 {"Title", PropHandle::Title, cppu::UnoType<OUString>::get(),
1451 css::beans::PropertyAttribute::TRANSIENT}},
1452 true};
1453 }();
1454 return HELPER;
1457 /*-************************************************************************************************************
1458 @short return propertysetinfo
1459 @descr You can call this method to get information about transient properties
1460 of this object.
1462 @attention You must use global lock (method use static variable) ... and it must be the shareable osl mutex of it.
1463 Because; our baseclass use this mutex to make his code threadsafe. We use our lock!
1464 So we could have two different mutex/lock mechanism at the same object.
1466 @seealso class OPropertySetHelper
1467 @seealso interface XPropertySet
1468 @seealso interface XMultiPropertySet
1469 @return reference to object with information [XPropertySetInfo]
1470 @threadsafe yes
1471 *//*-*************************************************************************************************************/
1472 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL Desktop::getPropertySetInfo()
1474 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1475 // Register transaction and reject wrong calls.
1476 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1478 // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
1479 // (Use method "getInfoHelper()".)
1480 static css::uno::Reference< css::beans::XPropertySetInfo > xInfo(
1481 cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ) );
1483 return xInfo;
1486 /*-************************************************************************************************************
1487 @short return current component of current frame
1488 @descr The desktop himself has no component. But every frame in subtree.
1489 If somewhere call getCurrentComponent() at this class, we try to find the right frame and
1490 then we try to become his component. It can be a VCL-component, the model or the controller
1491 of founded frame.
1493 @attention We don't work on internal member ... so we don't need any lock here.
1495 @seealso method getCurrentComponent();
1497 @param "xFrame", reference to valid frame in hierarchy. Method is not defined for invalid values.
1498 But we don't check these. It's an IMPL-method and caller must use it right!
1499 @return A reference to found component.
1501 @onerror A null reference is returned.
1502 @threadsafe yes
1503 *//*-*************************************************************************************************************/
1504 css::uno::Reference< css::lang::XComponent > Desktop::impl_getFrameComponent( const css::uno::Reference< css::frame::XFrame >& xFrame ) const
1506 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1507 // Register transaction and reject wrong calls.
1508 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1510 // Set default return value, if method failed.
1511 css::uno::Reference< css::lang::XComponent > xComponent;
1512 // Does no controller exists?
1513 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1514 if( !xController.is() )
1516 // Controller not exist - use the VCL-component.
1517 xComponent = xFrame->getComponentWindow();
1519 else
1521 // Does no model exists?
1522 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1523 if( xModel.is() )
1525 // Model exist - use the model as component.
1526 xComponent = xModel;
1528 else
1530 // Model not exist - use the controller as component.
1531 xComponent = xController;
1535 return xComponent;
1538 bool Desktop::impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList& lCalledListener)
1540 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1542 comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1543 if ( ! pContainer )
1544 return true;
1546 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1548 comphelper::OInterfaceIteratorHelper2 aIterator( *pContainer );
1549 while ( aIterator.hasMoreElements() )
1553 css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
1554 if ( ! xListener.is() )
1555 continue;
1556 xListener->queryTermination( aEvent );
1557 lCalledListener.push_back(xListener);
1559 catch( const css::frame::TerminationVetoException& )
1561 // first veto will stop the query loop.
1562 return false;
1564 catch( const css::uno::Exception& )
1566 // clean up container.
1567 // E.g. dead remote listener objects can make trouble otherwise.
1568 // Iterator implementation allows removing objects during it's used !
1569 aIterator.remove();
1573 return true;
1576 void Desktop::impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList& lCalledListener)
1578 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1580 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1581 for (const css::uno::Reference<css::frame::XTerminateListener>& xListener : lCalledListener)
1585 // Note: cancelTermination() is a new and optional interface method !
1586 css::uno::Reference< css::frame::XTerminateListener2 > xListenerGeneration2(xListener, css::uno::UNO_QUERY);
1587 if ( ! xListenerGeneration2.is() )
1588 continue;
1589 xListenerGeneration2->cancelTermination( aEvent );
1591 catch( const css::uno::Exception& )
1596 void Desktop::impl_sendTerminateToClipboard()
1598 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1600 comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1601 if ( ! pContainer )
1602 return;
1604 comphelper::OInterfaceIteratorHelper2 aIterator( *pContainer );
1605 while ( aIterator.hasMoreElements() )
1609 css::frame::XTerminateListener* pTerminateListener =
1610 static_cast< css::frame::XTerminateListener* >(aIterator.next());
1611 css::uno::Reference< css::lang::XServiceInfo > xInfo( pTerminateListener, css::uno::UNO_QUERY );
1612 if ( !xInfo.is() )
1613 continue;
1615 if ( xInfo->getImplementationName() != "com.sun.star.comp.svt.TransferableHelperTerminateListener" )
1616 continue;
1618 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1619 pTerminateListener->notifyTermination( aEvent );
1621 // don't notify twice
1622 aIterator.remove();
1624 catch( const css::uno::Exception& )
1626 // clean up container.
1627 // E.g. dead remote listener objects can make trouble otherwise.
1628 // Iterator implementation allows removing objects during it's used !
1629 aIterator.remove();
1634 void Desktop::impl_sendNotifyTerminationEvent()
1636 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1638 comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1639 if ( ! pContainer )
1640 return;
1642 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1644 comphelper::OInterfaceIteratorHelper2 aIterator( *pContainer );
1645 while ( aIterator.hasMoreElements() )
1649 static_cast< css::frame::XTerminateListener* >(aIterator.next())->notifyTermination( aEvent );
1651 catch( const css::uno::Exception& )
1653 // clean up container.
1654 // E.g. dead remote listener objects can make trouble otherwise.
1655 // Iterator implementation allows removing objects during it's used !
1656 aIterator.remove();
1661 bool Desktop::impl_closeFrames(bool bAllowUI)
1663 SolarMutexClearableGuard aReadLock;
1664 css::uno::Sequence< css::uno::Reference< css::frame::XFrame > > lFrames = m_aChildTaskContainer.getAllElements();
1665 aReadLock.clear();
1667 ::sal_Int32 c = lFrames.getLength();
1668 ::sal_Int32 i = 0;
1669 ::sal_Int32 nNonClosedFrames = 0;
1671 for( i=0; i<c; ++i )
1675 css::uno::Reference< css::frame::XFrame > xFrame = lFrames[i];
1677 // XController.suspend() will show a UI ...
1678 // Use it in case it was allowed from outside only.
1679 bool bSuspended = false;
1680 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1681 if ( bAllowUI && xController.is() )
1683 bSuspended = xController->suspend( true );
1684 if ( ! bSuspended )
1686 ++nNonClosedFrames;
1687 if(m_bSession)
1688 break;
1689 else
1690 continue;
1694 // Try to close frame (in case no UI was allowed without calling XController->suspend() before!)
1695 // But don't deliver ownership to any other one!
1696 // This method can be called again.
1697 css::uno::Reference< css::util::XCloseable > xClose( xFrame, css::uno::UNO_QUERY );
1698 if ( xClose.is() )
1702 xClose->close(false);
1704 catch(const css::util::CloseVetoException&)
1706 // Any internal process of this frame disagree with our request.
1707 // Safe this state but don't break these loop. Other frames has to be closed!
1708 ++nNonClosedFrames;
1710 // Reactivate controller.
1711 // It can happen that XController.suspend() returned true... but a registered close listener
1712 // threw these veto exception. Then the controller has to be reactivated. Otherwise
1713 // these document doesn't work any more.
1714 if ( bSuspended && xController.is())
1715 xController->suspend(false);
1718 // If interface XClosable interface exists and was used...
1719 // it's not allowed to use XComponent->dispose() also!
1720 continue;
1723 // XClosable not supported ?
1724 // Then we have to dispose these frame hardly.
1725 if ( xFrame.is() )
1726 xFrame->dispose();
1728 // Don't remove these frame from our child container!
1729 // A frame do it by itself inside close()/dispose() method.
1731 catch(const css::lang::DisposedException&)
1733 // Dispose frames are closed frames.
1734 // So we can count it here .-)
1738 // reset the session
1739 m_bSession = false;
1741 return (nNonClosedFrames < 1);
1744 } // namespace framework
1746 namespace {
1748 rtl::Reference<framework::Desktop> createDesktop(
1749 css::uno::Reference<css::uno::XComponentContext> const & context)
1751 SolarMutexGuard g; // tdf#114025 init with SolarMutex to avoid deadlock
1752 rtl::Reference<framework::Desktop> desktop(new framework::Desktop(context));
1753 desktop->constructorInit();
1754 return desktop;
1759 const rtl::Reference<framework::Desktop> & framework::getDesktop(
1760 css::uno::Reference<css::uno::XComponentContext> const & context)
1762 static auto const instance = createDesktop(context);
1763 return instance;
1766 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1767 com_sun_star_comp_framework_Desktop_get_implementation(
1768 css::uno::XComponentContext *context,
1769 css::uno::Sequence<css::uno::Any> const &)
1771 return cppu::acquire(framework::getDesktop(context).get());
1774 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */