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