Coverage Report

Created: 2026-03-31 11:00

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