Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/app/svmain.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 <sal/config.h>
21
#include <sal/log.hxx>
22
23
#include <cassert>
24
25
#include <osl/file.hxx>
26
#include <osl/signal.h>
27
28
#include <desktop/exithelper.h>
29
30
#include <comphelper/accessibleeventnotifier.hxx>
31
#include <comphelper/processfactory.hxx>
32
#include <comphelper/asyncnotification.hxx>
33
#include <drawinglayer/primitive2d/BufferedDecompositionFlusher.hxx>
34
#include <i18nlangtag/mslangid.hxx>
35
#include <unotools/syslocale.hxx>
36
#include <unotools/syslocaleoptions.hxx>
37
#include <utility>
38
#include <vcl/exceptiontypes.hxx>
39
#include <vcl/QueueInfo.hxx>
40
#include <vcl/svapp.hxx>
41
#include <vcl/vclmain.hxx>
42
#include <vcl/wrkwin.hxx>
43
#include <vcl/cvtgrf.hxx>
44
#include <vcl/scheduler.hxx>
45
#include <vcl/image.hxx>
46
#include <vcl/ImageTree.hxx>
47
#include <vcl/settings.hxx>
48
#include <vcl/toolkit/unowrap.hxx>
49
#include <tools/lazydelete.hxx>
50
#include <vcl/embeddedfontsmanager.hxx>
51
#include <vcl/toolkit/dialog.hxx>
52
#include <vcl/menu.hxx>
53
#include <vcl/virdev.hxx>
54
#include <vcl/print.hxx>
55
56
#include <bitmap/BlendFrameCache.hxx>
57
#include <debugevent.hxx>
58
#include <scrwnd.hxx>
59
#include <windowdev.hxx>
60
#include <svdata.hxx>
61
62
#ifdef _WIN32
63
#include <win/svsys.h>
64
#include <process.h>
65
#include <ole2.h>
66
#else
67
#include <stdlib.h>
68
#endif
69
70
#ifdef ANDROID
71
#include <cppuhelper/bootstrap.hxx>
72
#include <jni.h>
73
#endif
74
75
#include <impfontcache.hxx>
76
#include <salinst.hxx>
77
#include <vcl/svmain.hxx>
78
#include <dbggui.hxx>
79
#include <accmgr.hxx>
80
#include <font/PhysicalFontCollection.hxx>
81
#include <print.h>
82
#include <salsys.hxx>
83
#include <saltimer.hxx>
84
#include <displayconnectiondispatch.hxx>
85
86
#include <config_features.h>
87
#include <config_feature_opencl.h>
88
#include <systools/opensslinit.hxx>
89
90
#include <osl/process.h>
91
#include <com/sun/star/lang/XComponent.hpp>
92
#include <com/sun/star/frame/Desktop.hpp>
93
94
#ifdef _WIN32
95
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
96
#endif
97
98
#include <comphelper/lok.hxx>
99
#include <cppuhelper/implbase.hxx>
100
#include <uno/current_context.hxx>
101
102
#include <opencl/OpenCLZone.hxx>
103
#include <opengl/zone.hxx>
104
#include <skia/zone.hxx>
105
#include <watchdog.hxx>
106
107
#include <basegfx/utils/systemdependentdata.hxx>
108
#include <comphelper/diagnose_ex.hxx>
109
110
#if OSL_DEBUG_LEVEL > 0
111
#include <typeinfo>
112
#include <rtl/strbuf.hxx>
113
#endif
114
115
#ifdef LINUX
116
#include <unx/gendata.hxx>
117
#endif
118
119
using namespace ::com::sun::star;
120
121
static bool g_bIsLeanException;
122
123
static oslSignalAction VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
124
0
{
125
0
    static volatile bool bIn = false;
126
127
    // if we crash again, bail out immediately
128
0
    if ( bIn  || g_bIsLeanException)
129
0
        return osl_Signal_ActCallNextHdl;
130
131
0
    ExceptionCategory nVCLException = ExceptionCategory::NONE;
132
133
    // UAE
134
0
    if ( (pInfo->Signal == osl_Signal_AccessViolation)     ||
135
0
         (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
136
0
         (pInfo->Signal == osl_Signal_FloatDivideByZero)   ||
137
0
         (pInfo->Signal == osl_Signal_DebugBreak) )
138
0
    {
139
0
        nVCLException = ExceptionCategory::System;
140
#if HAVE_FEATURE_OPENGL
141
        if (OpenGLZone::isInZone())
142
            OpenGLZone::hardDisable();
143
#endif
144
#if HAVE_FEATURE_SKIA
145
        if (SkiaZone::isInZone())
146
            SkiaZone::hardDisable();
147
#endif
148
#if HAVE_FEATURE_OPENCL
149
        if (OpenCLZone::isInZone())
150
        {
151
            OpenCLZone::hardDisable();
152
#ifdef _WIN32
153
            if (OpenCLInitialZone::isInZone())
154
                TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART);
155
#endif
156
        }
157
#endif
158
0
    }
159
160
    // DISPLAY-Unix
161
0
    if ((pInfo->Signal == osl_Signal_User) &&
162
0
        (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
163
0
        nVCLException = ExceptionCategory::UserInterface;
164
165
0
    if ( nVCLException != ExceptionCategory::NONE )
166
0
    {
167
0
        bIn = true;
168
169
0
        vcl::SolarMutexTryAndBuyGuard aLock;
170
0
        if( aLock.isAcquired())
171
0
        {
172
            // do not stop timer because otherwise the UAE-Box will not be painted as well
173
0
            ImplSVData* pSVData = ImplGetSVData();
174
0
            if ( pSVData->mpApp )
175
0
            {
176
0
                SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
177
0
                Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
178
0
                pSVData->mpApp->Exception( nVCLException );
179
0
                Application::SetSystemWindowMode( nOldMode );
180
0
            }
181
0
        }
182
0
        bIn = false;
183
0
    }
184
185
0
    return osl_Signal_ActCallNextHdl;
186
187
0
}
188
189
int ImplSVMain()
190
0
{
191
    // The 'real' SVMain()
192
0
    ImplSVData* pSVData = ImplGetSVData();
193
194
0
    SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" );
195
196
0
    if ( IsVCLInit() )
197
0
        return EXIT_SUCCESS;
198
199
0
#if !defined(_WIN32) && !defined(SYSTEM_OPENSSL)
200
0
    static constexpr OUString name(u"SSL_CERT_FILE"_ustr);
201
0
    OUString temp;
202
0
    if (osl_getEnvironment(name.pData, &temp.pData) == osl_Process_E_NotFound)
203
0
    {
204
        // Try to point bundled OpenSSL to some system certificate file
205
        // ... this only works if the client actually calls
206
        // SSL_CTX_set_default_verify_paths() or similar; e.g. python ssl.
207
0
        char const*const path = GetCABundleFile();
208
0
        if (path == nullptr) {
209
0
            SAL_WARN("vcl", "no OpenSSL CA certificate bundle found");
210
0
        } else {
211
0
            OUString const filepath(::rtl::OStringToOUString(
212
0
                ::std::string_view(path), osl_getThreadTextEncoding()));
213
0
            osl_setEnvironment(name.pData, filepath.pData);
214
0
        }
215
0
    }
216
0
#endif
217
218
0
    if ( !InitVCL() )
219
0
        return EXIT_FAILURE;
220
221
0
    return GetSalInstance()->SVMainRun();
222
0
}
223
224
int ImplSVMainRun()
225
0
{
226
0
    ImplSVData* pSVData = ImplGetSVData();
227
228
0
    int nReturn = EXIT_FAILURE;
229
230
0
    if( IsVCLInit() )
231
0
    {
232
        // call application main
233
0
        pSVData->maAppData.mbInAppMain = true;
234
0
        nReturn = pSVData->mpApp->Main();
235
0
        pSVData->maAppData.mbInAppMain = false;
236
0
    }
237
238
0
    if( pSVData->mxDisplayConnection.is() )
239
0
    {
240
0
        pSVData->mxDisplayConnection->terminate();
241
0
        pSVData->mxDisplayConnection.clear();
242
0
    }
243
244
0
    WatchdogThread::stop();
245
0
    DeInitVCL();
246
247
0
    return nReturn;
248
0
}
249
250
int SVMain()
251
0
{
252
0
    return ImplSVMain();
253
0
}
254
255
// This variable is set when no Application object has been instantiated
256
// before InitVCL is called
257
static Application *        pOwnSvApp = nullptr;
258
259
// Exception handler. pExceptionHandler != NULL => VCL already inited
260
static oslSignalHandler pExceptionHandler = nullptr;
261
262
bool IsVCLInit()
263
110
{
264
110
    ImplSVData* pSVData = ImplGetSVData();
265
110
    return  pExceptionHandler != nullptr &&
266
6
            pSVData->mpApp != nullptr &&
267
6
            pSVData->mpDefInst != nullptr;
268
110
}
269
270
#ifdef DBG_UTIL
271
namespace vclmain
272
{
273
    bool isAlive()
274
    {
275
        return ImplGetSVData()->mpDefInst;
276
    }
277
}
278
#endif
279
280
281
bool InitVCL()
282
104
{
283
104
    if (IsVCLInit())
284
0
    {
285
0
        SAL_INFO("vcl.app", "Double initialization of vcl");
286
0
        return true;
287
0
    }
288
289
104
    if( pExceptionHandler != nullptr )
290
0
        return false;
291
292
104
    EmbeddedFontsManager::clearTemporaryFontFiles();
293
294
104
    if( !ImplGetSVData()->mpApp )
295
104
    {
296
104
        pOwnSvApp = new Application();
297
104
    }
298
299
104
    ImplSVData* pSVData = ImplGetSVData();
300
301
    // remember Main-Thread-Id
302
104
    pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
303
304
    // Initialize Sal
305
104
    pSVData->mpDefInst = CreateSalInstance();
306
104
    if ( !pSVData->mpDefInst )
307
0
        return false;
308
104
    pSVData->mpDefInst->AcquireYieldMutex();
309
310
    // Initialize application instance (should be done after initialization of VCL SAL part)
311
104
    if (pSVData->mpApp)
312
104
    {
313
        // call init to initialize application class
314
        // soffice/sfx implementation creates the global service manager
315
104
        pSVData->mpApp->Init();
316
104
    }
317
318
104
    try
319
104
    {
320
        //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can
321
        //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL
322
        //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python)
323
        //to match their translations to our preferred UI language
324
104
        OUString aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(u".UTF-8"));
325
104
        if (!aLocaleString.isEmpty())
326
104
        {
327
104
            MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was
328
104
            OUString envVar(u"LANGUAGE"_ustr);
329
104
            osl_setEnvironment(envVar.pData, aLocaleString.pData);
330
104
        }
331
104
    }
332
104
    catch (const uno::Exception &)
333
104
    {
334
0
        TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:");
335
0
    }
336
337
104
    pSVData->mpDefInst->AfterAppInit();
338
339
    // Fetch AppFileName and make it absolute before the workdir changes...
340
104
    OUString aExeFileName;
341
104
    osl_getExecutableFile( &aExeFileName.pData );
342
343
    // convert path to native file format
344
104
    OUString aNativeFileName;
345
104
    osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
346
104
    pSVData->maAppData.mxAppFileName = aNativeFileName;
347
348
    // Initialize global data
349
104
    pSVData->maGDIData.mxScreenFontList = std::make_shared<vcl::font::PhysicalFontCollection>();
350
104
    pSVData->maGDIData.mxScreenFontCache = std::make_shared<ImplFontCache>();
351
104
    pSVData->maGDIData.mxGrfConverter.reset(new GraphicConverter);
352
353
104
    g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr;
354
    // Set exception handler
355
104
    pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr);
356
357
#ifndef NDEBUG
358
    DbgGUIInitSolarMutexCheck();
359
#endif
360
361
#if OSL_DEBUG_LEVEL > 0
362
    DebugEventInjector::getCreate();
363
#endif
364
365
104
#ifndef _WIN32
366
    // Clear startup notification details for child processes
367
    // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
368
104
    unsetenv("DESKTOP_STARTUP_ID");
369
104
#endif
370
371
104
    return true;
372
104
}
373
374
namespace
375
{
376
377
/** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
378
  crash at exit in some special cases when a11y is enabled (e.g., when
379
  a bundled extension is registered/deregistered during startup, forcing exit
380
  while the app is still in splash screen.)
381
 */
382
class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener>
383
{
384
    virtual void SAL_CALL disposing(lang::EventObject const& rSource) override;
385
};
386
387
void
388
VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
389
0
{
390
0
    ImplSVData* const pSVData = ImplGetSVData();
391
0
    if (pSVData && pSVData->mpUnoWrapper)
392
0
    {
393
0
        pSVData->mpUnoWrapper->Destroy();
394
0
        pSVData->mpUnoWrapper = nullptr;
395
0
    }
396
0
}
397
398
}
399
400
void DeInitVCL()
401
0
{
402
    // The LOK Windows map container should be empty
403
0
    assert(vcl::Window::IsLOKWindowsEmpty());
404
405
    //rhbz#1444437, when using LibreOffice like a library you can't realistically
406
    //tear everything down and recreate them on the next call, there's too many
407
    //(c++) singletons that point to stuff that gets deleted during shutdown
408
    //which won't be recreated on restart.
409
0
    if (comphelper::LibreOfficeKit::isActive())
410
0
        return;
411
412
0
    {
413
0
        SolarMutexReleaser r; // unblock threads blocked on that so we can join
414
0
        ::comphelper::JoinAsyncEventNotifiers();
415
0
    }
416
0
    ImplSVData* pSVData = ImplGetSVData();
417
418
    // This is a hack to work around the problem of the asynchronous nature
419
    // of bridging accessibility through Java: on shutdown there might still
420
    // be some events in the AWT EventQueue, which need the SolarMutex which
421
    // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
422
    // here ..
423
0
    if (pSVData->mxAccessBridge.is())
424
0
    {
425
0
        {
426
0
            SolarMutexReleaser aReleaser;
427
0
            pSVData->mxAccessBridge->dispose();
428
0
        }
429
0
        pSVData->mxAccessBridge.clear();
430
0
    }
431
432
    // lp#1560328: clear cache before disposing rest of VCL
433
0
    if(pSVData->mpBlendFrameCache)
434
0
        pSVData->mpBlendFrameCache->m_aLastResult = Bitmap();
435
0
    pSVData->mbDeInit = true;
436
437
    // Some events may need to access objects destroyed in ImplDeleteOnDeInit, so process them first
438
0
    Scheduler::ProcessEventsToIdle();
439
440
0
    {
441
        // unblock we will wait for things that want to take the SolarMutex on another thread
442
0
        SolarMutexReleaser aReleaser;
443
0
        drawinglayer::primitive2d::BufferedDecompositionFlusher::shutdown();
444
0
    }
445
446
0
    tools::DeleteOnDeinitBase::ImplDeleteOnDeInit();
447
448
#if OSL_DEBUG_LEVEL > 0
449
    OStringBuffer aBuf( 256 );
450
    aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
451
    tools::Long nTopWindowCount = Application::GetTopWindowCount();
452
    tools::Long nBadTopWindows = nTopWindowCount;
453
    for( tools::Long i = 0; i < nTopWindowCount; i++ )
454
    {
455
        vcl::Window* pWin = Application::GetTopWindow( i );
456
        // default window will be destroyed further down
457
        // but may still be useful during deinit up to that point
458
        if( pWin == pSVData->mpDefaultWin )
459
            nBadTopWindows--;
460
        else
461
        {
462
            aBuf.append( "text = \""
463
                + OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() )
464
                + "\" type = \""
465
                + typeid(*pWin).name()
466
                + "\", ptr = 0x"
467
                + OString::number(reinterpret_cast<sal_Int64>( pWin ), 16 )
468
                + "\n" );
469
        }
470
    }
471
    SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
472
#endif
473
474
0
    ImageTree::get().shutdown();
475
476
0
    osl_removeSignalHandler( pExceptionHandler);
477
0
    pExceptionHandler = nullptr;
478
479
    // free global data
480
0
    pSVData->maGDIData.mxGrfConverter.reset();
481
482
    // prevent unnecessary painting during Scheduler shutdown
483
    // as this processes all pending events in debug builds.
484
0
    ImplGetSystemDependentDataManager().flushAll();
485
486
#if defined _WIN32
487
    // See GetSystemClipboard (vcl/source/treelist/transfer2.cxx):
488
    if (auto const comp = css::uno::Reference<css::lang::XComponent>(
489
            pSVData->m_xSystemClipboard, css::uno::UNO_QUERY))
490
    {
491
        SolarMutexReleaser r; // unblock pending "clipboard content changed" notifications
492
        comp->dispose(); // will use s_aClipboardSingletonMutex for CWinClipboard
493
    }
494
    pSVData->m_xSystemClipboard.clear();
495
#endif
496
497
0
    Scheduler::ImplDeInitScheduler();
498
499
0
    pSVData->mpWinData->maMsgBoxImgList.clear();
500
0
    pSVData->maCtrlData.maCheckImgList.clear();
501
0
    pSVData->maCtrlData.maRadioImgList.clear();
502
0
    pSVData->maCtrlData.moDisclosurePlus.reset();
503
0
    pSVData->maCtrlData.moDisclosureMinus.reset();
504
0
    pSVData->mpDefaultWin.disposeAndClear();
505
506
#ifndef NDEBUG
507
    DbgGUIDeInitSolarMutexCheck();
508
#endif
509
510
0
    if ( pSVData->mpUnoWrapper )
511
0
    {
512
0
        try
513
0
        {
514
0
            uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
515
0
                    comphelper::getProcessComponentContext() );
516
0
            xDesktop->addEventListener(new VCLUnoWrapperDeleter);
517
0
        }
518
0
        catch (uno::Exception const&)
519
0
        {
520
            // ignore
521
0
        }
522
0
    }
523
524
0
    if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
525
0
    {
526
0
        SolarMutexReleaser aReleaser;
527
        // call deinit to deinitialize application class
528
        // soffice/sfx implementation disposes the global service manager
529
        // Warning: After this call you can't call uno services
530
0
        if( pSVData->mpApp )
531
0
        {
532
0
            pSVData->mpApp->DeInit();
533
0
        }
534
0
        if( pSVData->maDeInitHook.IsSet() )
535
0
        {
536
0
            pSVData->maDeInitHook.Call(nullptr);
537
0
        }
538
0
    }
539
540
0
    if ( pSVData->maAppData.mxSettings )
541
0
    {
542
0
        if ( pSVData->maAppData.mpCfgListener )
543
0
        {
544
0
            pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
545
0
            delete pSVData->maAppData.mpCfgListener;
546
0
        }
547
548
0
        pSVData->maAppData.mxSettings.reset();
549
0
    }
550
0
    if ( pSVData->maAppData.mpAccelMgr )
551
0
    {
552
0
        delete pSVData->maAppData.mpAccelMgr;
553
0
        pSVData->maAppData.mpAccelMgr = nullptr;
554
0
    }
555
0
    pSVData->maAppData.maKeyListeners.clear();
556
0
    pSVData->mpBlendFrameCache.reset();
557
558
0
    ImplDeletePrnQueueList();
559
560
    // destroy all Sal interfaces before destroying the instance
561
    // and thereby unloading the plugin
562
0
    pSVData->mpSalSystem.reset();
563
0
    assert( !pSVData->maSchedCtx.mpSalTimer );
564
0
    delete pSVData->maSchedCtx.mpSalTimer;
565
0
    pSVData->maSchedCtx.mpSalTimer = nullptr;
566
567
0
    pSVData->mpDefaultWin = nullptr;
568
0
    pSVData->mpIntroWindow = nullptr;
569
0
    pSVData->maAppData.mpActivePopupMenu = nullptr;
570
0
    pSVData->maAppData.mpWheelWindow = nullptr;
571
0
    pSVData->maGDIData.mpFirstWinGraphics = nullptr;
572
0
    pSVData->maGDIData.mpLastWinGraphics = nullptr;
573
0
    pSVData->maGDIData.mpFirstVirGraphics = nullptr;
574
0
    pSVData->maGDIData.mpLastVirGraphics = nullptr;
575
0
    pSVData->maGDIData.mpFirstPrnGraphics = nullptr;
576
0
    pSVData->maGDIData.mpLastPrnGraphics = nullptr;
577
0
    pSVData->maGDIData.mpFirstVirDev = nullptr;
578
0
    pSVData->maGDIData.mpFirstPrinter = nullptr;
579
0
    pSVData->maFrameData.mpFirstFrame = nullptr;
580
0
    pSVData->maFrameData.mpAppWin = nullptr;
581
0
    pSVData->maFrameData.mpActiveApplicationFrame = nullptr;
582
0
    pSVData->mpWinData->mpCaptureWin = nullptr;
583
0
    pSVData->mpWinData->mpLastDeacWin = nullptr;
584
0
    pSVData->mpWinData->mpFirstFloat = nullptr;
585
0
    pSVData->mpWinData->mpExecuteDialogs.clear();
586
0
    pSVData->mpWinData->mpExtTextInputWin = nullptr;
587
0
    pSVData->mpWinData->mpTrackWin = nullptr;
588
0
    pSVData->mpWinData->mpAutoScrollWin = nullptr;
589
0
    pSVData->mpWinData->mpLastWheelWindow = nullptr;
590
591
0
    pSVData->maGDIData.mxScreenFontList.reset();
592
0
    pSVData->maGDIData.mxScreenFontCache.reset();
593
0
    pSVData->dropCaches();
594
595
0
    comphelper::AccessibleEventNotifier::shutdown();
596
597
    // Deinit Sal
598
0
    if (pSVData->mpDefInst)
599
0
    {
600
0
        pSVData->mpDefInst->ReleaseYieldMutex(true);
601
0
        DestroySalInstance( pSVData->mpDefInst );
602
0
        pSVData->mpDefInst = nullptr;
603
0
    }
604
605
    // This only works on Linux. On Mac and Windows I get very
606
    // weird segment violations.
607
0
#if defined LINUX
608
0
    delete pSVData->mpSalData;
609
0
    pSVData->mpSalData = nullptr;
610
0
#endif
611
612
0
    if( pOwnSvApp )
613
0
    {
614
0
        delete pOwnSvApp;
615
0
        pOwnSvApp = nullptr;
616
0
    }
617
618
0
    EmbeddedFontsManager::clearTemporaryFontFiles();
619
0
}
620
621
namespace {
622
623
// only one call is allowed
624
struct WorkerThreadData
625
{
626
    oslWorkerFunction   pWorker;
627
    void *              pThreadData;
628
    WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
629
6
        : pWorker( pWorker_ )
630
6
        , pThreadData( pThreadData_ )
631
6
    {
632
6
    }
633
};
634
635
}
636
637
#ifdef _WIN32
638
static HANDLE hThreadID = nullptr;
639
static unsigned __stdcall threadmain(void* pArgs)
640
{
641
    OleInitialize( nullptr );
642
    static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
643
    delete static_cast<WorkerThreadData*>(pArgs);
644
    OleUninitialize();
645
    hThreadID = nullptr;
646
    return 0;
647
}
648
#else
649
static oslThread hThreadID = nullptr;
650
extern "C"
651
{
652
static void MainWorkerFunction( void* pArgs )
653
6
{
654
6
    static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
655
6
    delete static_cast<WorkerThreadData*>(pArgs);
656
6
    hThreadID = nullptr;
657
6
}
658
} // extern "C"
659
#endif
660
661
void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
662
6
{
663
#ifdef _WIN32
664
    // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
665
666
    hThreadID = reinterpret_cast<HANDLE>(_beginthreadex(
667
        nullptr,       // no security handle
668
        0,          // stacksize 0 means default
669
        threadmain,    // thread worker function
670
        new WorkerThreadData( pWorker, pThreadData ),       // arguments for worker function
671
        0,          // 0 means: create immediately otherwise use CREATE_SUSPENDED
672
        nullptr ));   // thread id to fill
673
#else
674
6
    hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
675
6
#endif
676
6
}
677
678
void JoinMainLoopThread()
679
0
{
680
0
    if( hThreadID )
681
0
    {
682
#ifdef _WIN32
683
        WaitForSingleObject(hThreadID, INFINITE);
684
#else
685
0
        osl_joinWithThread(hThreadID);
686
0
        osl_destroyThread( hThreadID );
687
0
#endif
688
0
    }
689
0
}
690
691
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */