build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / app / svmain.cxx
bloba74279686a436f7a6d0946f37447e2903c4ceb28
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cassert>
24 #include <osl/file.hxx>
25 #include <osl/signal.h>
27 #include <desktop/exithelper.h>
29 #include <tools/debug.hxx>
30 #include <tools/resmgr.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/asyncnotification.hxx>
35 #include <unotools/syslocaleoptions.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/wrkwin.hxx>
38 #include <vcl/cvtgrf.hxx>
39 #include <vcl/scheduler.hxx>
40 #include <vcl/image.hxx>
41 #include <vcl/ImageTree.hxx>
42 #include <vcl/settings.hxx>
43 #include <vcl/unowrap.hxx>
44 #include <vcl/commandinfoprovider.hxx>
45 #include <vcl/configsettings.hxx>
46 #include <vcl/lazydelete.hxx>
47 #include <vcl/embeddedfontshelper.hxx>
48 #include <vcl/debugevent.hxx>
50 #ifdef _WIN32
51 #include <svsys.h>
52 #include <process.h>
53 #include <ole2.h>
54 #endif
56 #ifdef ANDROID
57 #include <cppuhelper/bootstrap.hxx>
58 #include <jni.h>
59 #endif
61 #include "salinst.hxx"
62 #include "salwtype.hxx"
63 #include "svdata.hxx"
64 #include <vcl/svmain.hxx>
65 #include "dbggui.hxx"
66 #include "accmgr.hxx"
67 #include "outdev.h"
68 #include "fontinstance.hxx"
69 #include "PhysicalFontCollection.hxx"
70 #include "print.h"
71 #include "salgdi.hxx"
72 #include "salsys.hxx"
73 #include "saltimer.hxx"
74 #include "salimestatus.hxx"
75 #include "displayconnectiondispatch.hxx"
77 #include <config_features.h>
78 #if HAVE_FEATURE_OPENGL
79 #include <vcl/opengl/OpenGLContext.hxx>
80 #endif
82 #include <osl/process.h>
83 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
84 #include <com/sun/star/lang/XComponent.hpp>
85 #include <com/sun/star/frame/Desktop.hpp>
87 #include <cppuhelper/implbase.hxx>
88 #include <uno/current_context.hxx>
90 #include <opencl/OpenCLZone.hxx>
91 #include <opengl/zone.hxx>
92 #include <opengl/watchdog.hxx>
94 #if OSL_DEBUG_LEVEL > 0
95 #include <typeinfo>
96 #include <rtl/strbuf.hxx>
97 #endif
99 using namespace ::com::sun::star;
101 static bool g_bIsLeanException;
103 static bool isInitVCL();
105 oslSignalAction SAL_CALL VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
107 static volatile bool bIn = false;
109 // if we crash again, bail out immediately
110 if ( bIn || g_bIsLeanException)
111 return osl_Signal_ActCallNextHdl;
113 ExceptionCategory nVCLException = ExceptionCategory::NONE;
115 // UAE
116 if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
117 (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
118 (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
119 (pInfo->Signal == osl_Signal_DebugBreak) )
121 nVCLException = ExceptionCategory::System;
122 #if HAVE_FEATURE_OPENGL
123 if (OpenGLZone::isInZone())
124 OpenGLZone::hardDisable();
125 #endif
126 #if HAVE_FEATURE_OPENCL
127 if (OpenCLZone::isInZone())
129 OpenCLZone::hardDisable();
130 #ifdef _WIN32
131 if (OpenCLZone::isInInitialTest())
132 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART);
133 #endif
135 #endif
138 // RC
139 if ((pInfo->Signal == osl_Signal_User) &&
140 (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
141 nVCLException = ExceptionCategory::ResourceNotLoaded;
143 // DISPLAY-Unix
144 if ((pInfo->Signal == osl_Signal_User) &&
145 (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
146 nVCLException = ExceptionCategory::UserInterface;
148 if ( nVCLException != ExceptionCategory::NONE )
150 bIn = true;
152 SolarMutexGuard aLock;
154 // do not stop timer because otherwise the UAE-Box will not be painted as well
155 ImplSVData* pSVData = ImplGetSVData();
156 if ( pSVData->mpApp )
158 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
159 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
160 pSVData->mpApp->Exception( nVCLException );
161 Application::SetSystemWindowMode( nOldMode );
163 bIn = false;
166 return osl_Signal_ActCallNextHdl;
170 int ImplSVMain()
172 // The 'real' SVMain()
173 ImplSVData* pSVData = ImplGetSVData();
175 SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" );
177 int nReturn = EXIT_FAILURE;
179 bool bInit = isInitVCL() || InitVCL();
181 if( bInit )
183 // call application main
184 pSVData->maAppData.mbInAppMain = true;
185 nReturn = pSVData->mpApp->Main();
186 pSVData->maAppData.mbInAppMain = false;
189 if( pSVData->mxDisplayConnection.is() )
191 pSVData->mxDisplayConnection->terminate();
192 pSVData->mxDisplayConnection.clear();
195 // This is a hack to work around the problem of the asynchronous nature
196 // of bridging accessibility through Java: on shutdown there might still
197 // be some events in the AWT EventQueue, which need the SolarMutex which
198 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
199 // here ..
200 if( pSVData->mxAccessBridge.is() )
203 SolarMutexReleaser aReleaser;
204 pSVData->mxAccessBridge->dispose();
206 pSVData->mxAccessBridge.clear();
209 #if HAVE_FEATURE_OPENGL
210 OpenGLWatchdogThread::stop();
211 #endif
212 DeInitVCL();
214 return nReturn;
217 int SVMain()
219 int nRet;
220 if( !Application::IsConsoleOnly() && ImplSVMainHook( &nRet ) )
221 return nRet;
222 else
223 return ImplSVMain();
226 // This variable is set when no Application object has been instantiated
227 // before InitVCL is called
228 static Application * pOwnSvApp = nullptr;
230 // Exception handler. pExceptionHandler != NULL => VCL already inited
231 static oslSignalHandler pExceptionHandler = nullptr;
233 class DesktopEnvironmentContext: public cppu::WeakImplHelper< css::uno::XCurrentContext >
235 public:
236 explicit DesktopEnvironmentContext( const css::uno::Reference< css::uno::XCurrentContext > & ctx)
237 : m_xNextContext( ctx ) {}
239 // XCurrentContext
240 virtual css::uno::Any SAL_CALL getValueByName( const OUString& Name )
241 throw (css::uno::RuntimeException, std::exception) override;
243 private:
244 css::uno::Reference< css::uno::XCurrentContext > m_xNextContext;
247 uno::Any SAL_CALL DesktopEnvironmentContext::getValueByName( const OUString& Name) throw (uno::RuntimeException, std::exception)
249 uno::Any retVal;
251 if ( Name == "system.desktop-environment" )
253 retVal = uno::makeAny( Application::GetDesktopEnvironment() );
255 else if( m_xNextContext.is() )
257 // Call next context in chain if found
258 retVal = m_xNextContext->getValueByName( Name );
260 return retVal;
263 static bool isInitVCL()
265 ImplSVData* pSVData = ImplGetSVData();
266 return pExceptionHandler != nullptr &&
267 pSVData->mpApp != nullptr &&
268 pSVData->mpDefInst != nullptr;
271 bool InitVCL()
273 if( pExceptionHandler != nullptr )
274 return false;
276 EmbeddedFontsHelper::clearTemporaryFontFiles();
278 if( !ImplGetSVData()->mpApp )
280 pOwnSvApp = new Application();
282 InitSalMain();
284 ImplSVData* pSVData = ImplGetSVData();
286 // remember Main-Thread-Id
287 pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
289 // Initialize Sal
290 pSVData->mpDefInst = CreateSalInstance();
291 if ( !pSVData->mpDefInst )
292 return false;
294 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
295 css::uno::setCurrentContext(
296 new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
298 // Initialize application instance (should be done after initialization of VCL SAL part)
299 if( pSVData->mpApp )
300 // call init to initialize application class
301 // soffice/sfx implementation creates the global service manager
302 pSVData->mpApp->Init();
304 pSVData->mpDefInst->AfterAppInit();
306 // Fetch AppFileName and make it absolute before the workdir changes...
307 OUString aExeFileName;
308 osl_getExecutableFile( &aExeFileName.pData );
310 // convert path to native file format
311 OUString aNativeFileName;
312 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
313 pSVData->maAppData.mpAppFileName = new OUString( aNativeFileName );
315 // Initialize global data
316 pSVData->maGDIData.mpScreenFontList = new PhysicalFontCollection;
317 pSVData->maGDIData.mpScreenFontCache = new ImplFontCache;
318 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
320 g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr;
321 // Set exception handler
322 pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr);
324 #ifdef DBG_UTIL
325 DbgGUIInitSolarMutexCheck();
326 #endif
328 #if OSL_DEBUG_LEVEL > 0
329 DebugEventInjector::getCreate();
330 #endif
332 return true;
335 namespace
338 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
339 crash at exit in some special cases when a11y is enabled (e.g., when
340 a bundled extension is registered/deregistered during startup, forcing exit
341 while the app is still in splash screen.)
343 class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener>
345 virtual void SAL_CALL disposing(lang::EventObject const& rSource) throw(uno::RuntimeException, std::exception) override;
348 void
349 VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
350 throw(uno::RuntimeException, std::exception)
352 ImplSVData* const pSVData = ImplGetSVData();
353 if (pSVData && pSVData->mpUnoWrapper)
355 pSVData->mpUnoWrapper->Destroy();
356 pSVData->mpUnoWrapper = nullptr;
362 void DeInitVCL()
365 SolarMutexReleaser r; // unblock threads blocked on that so we can join
366 ::comphelper::JoinAsyncEventNotifiers();
368 ImplSVData* pSVData = ImplGetSVData();
369 // lp#1560328: clear cache before disposing rest of VCL
370 if(pSVData->mpBlendFrameCache)
371 pSVData->mpBlendFrameCache->m_aLastResult.Clear();
372 pSVData->mbDeInit = true;
374 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
376 // give ime status a chance to destroy its own windows
377 delete pSVData->mpImeStatus;
378 pSVData->mpImeStatus = nullptr;
380 #if OSL_DEBUG_LEVEL > 0
381 OStringBuffer aBuf( 256 );
382 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
383 long nTopWindowCount = Application::GetTopWindowCount();
384 long nBadTopWindows = nTopWindowCount;
385 for( long i = 0; i < nTopWindowCount; i++ )
387 vcl::Window* pWin = Application::GetTopWindow( i );
388 // default window will be destroyed further down
389 // but may still be useful during deinit up to that point
390 if( pWin == pSVData->mpDefaultWin )
391 nBadTopWindows--;
392 else
394 aBuf.append( "text = \"" );
395 aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
396 aBuf.append( "\" type = \"" );
397 aBuf.append( typeid(*pWin).name() );
398 aBuf.append( "\", ptr = 0x" );
399 aBuf.append( sal_Int64( pWin ), 16 );
400 aBuf.append( "\n" );
403 SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
404 #endif
406 ImageTree::get().shutdown();
408 osl_removeSignalHandler( pExceptionHandler);
409 pExceptionHandler = nullptr;
411 // free global data
412 delete pSVData->maGDIData.mpGrfConverter;
414 if( pSVData->mpSettingsConfigItem )
416 delete pSVData->mpSettingsConfigItem;
417 pSVData->mpSettingsConfigItem = nullptr;
420 Scheduler::ImplDeInitScheduler();
422 if ( pSVData->maWinData.mpMsgBoxImgList )
424 delete pSVData->maWinData.mpMsgBoxImgList;
425 pSVData->maWinData.mpMsgBoxImgList = nullptr;
427 if ( pSVData->maCtrlData.mpCheckImgList )
429 delete pSVData->maCtrlData.mpCheckImgList;
430 pSVData->maCtrlData.mpCheckImgList = nullptr;
432 if ( pSVData->maCtrlData.mpRadioImgList )
434 delete pSVData->maCtrlData.mpRadioImgList;
435 pSVData->maCtrlData.mpRadioImgList = nullptr;
437 if ( pSVData->maCtrlData.mpPinImgList )
439 delete pSVData->maCtrlData.mpPinImgList;
440 pSVData->maCtrlData.mpPinImgList = nullptr;
442 if ( pSVData->maCtrlData.mpSplitHPinImgList )
444 delete pSVData->maCtrlData.mpSplitHPinImgList;
445 pSVData->maCtrlData.mpSplitHPinImgList = nullptr;
447 if ( pSVData->maCtrlData.mpSplitVPinImgList )
449 delete pSVData->maCtrlData.mpSplitVPinImgList;
450 pSVData->maCtrlData.mpSplitVPinImgList = nullptr;
452 if ( pSVData->maCtrlData.mpDisclosurePlus )
454 delete pSVData->maCtrlData.mpDisclosurePlus;
455 pSVData->maCtrlData.mpDisclosurePlus = nullptr;
457 if ( pSVData->maCtrlData.mpDisclosureMinus )
459 delete pSVData->maCtrlData.mpDisclosureMinus;
460 pSVData->maCtrlData.mpDisclosureMinus = nullptr;
462 pSVData->mpDefaultWin.disposeAndClear();
464 #ifdef DBG_UTIL
465 DbgGUIDeInitSolarMutexCheck();
466 #endif
468 if ( pSVData->mpUnoWrapper )
472 uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
473 comphelper::getProcessComponentContext() );
474 xDesktop->addEventListener(new VCLUnoWrapperDeleter());
476 catch (uno::Exception const&)
478 // ignore
482 if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
484 SolarMutexReleaser aReleaser;
485 // call deinit to deinitialize application class
486 // soffice/sfx implementation disposes the global service manager
487 // Warning: After this call you can't call uno services
488 if( pSVData->mpApp )
490 pSVData->mpApp->DeInit();
492 if( pSVData->maDeInitHook.IsSet() )
494 pSVData->maDeInitHook.Call(nullptr);
498 if ( pSVData->maAppData.mpSettings )
500 if ( pSVData->maAppData.mpCfgListener )
502 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
503 delete pSVData->maAppData.mpCfgListener;
506 delete pSVData->maAppData.mpSettings;
507 pSVData->maAppData.mpSettings = nullptr;
509 if ( pSVData->maAppData.mpAccelMgr )
511 delete pSVData->maAppData.mpAccelMgr;
512 pSVData->maAppData.mpAccelMgr = nullptr;
514 if ( pSVData->maAppData.mpAppFileName )
516 delete pSVData->maAppData.mpAppFileName;
517 pSVData->maAppData.mpAppFileName = nullptr;
519 if ( pSVData->maAppData.mpAppName )
521 delete pSVData->maAppData.mpAppName;
522 pSVData->maAppData.mpAppName = nullptr;
524 if ( pSVData->maAppData.mpDisplayName )
526 delete pSVData->maAppData.mpDisplayName;
527 pSVData->maAppData.mpDisplayName = nullptr;
529 if ( pSVData->maAppData.mpToolkitName )
531 delete pSVData->maAppData.mpToolkitName;
532 pSVData->maAppData.mpToolkitName = nullptr;
534 if ( pSVData->maAppData.mpEventListeners )
536 delete pSVData->maAppData.mpEventListeners;
537 pSVData->maAppData.mpEventListeners = nullptr;
539 if ( pSVData->maAppData.mpKeyListeners )
541 delete pSVData->maAppData.mpKeyListeners;
542 pSVData->maAppData.mpKeyListeners = nullptr;
545 if ( pSVData->maAppData.mpFirstHotKey )
546 ImplFreeHotKeyData();
547 if ( pSVData->maAppData.mpFirstEventHook )
548 ImplFreeEventHookData();
550 if (pSVData->mpBlendFrameCache)
552 delete pSVData->mpBlendFrameCache;
553 pSVData->mpBlendFrameCache = nullptr;
556 if (pSVData->mpCommandInfoProvider)
558 pSVData->mpCommandInfoProvider->dispose();
559 pSVData->mpCommandInfoProvider = nullptr;
562 ImplDeletePrnQueueList();
563 delete pSVData->maGDIData.mpScreenFontList;
564 pSVData->maGDIData.mpScreenFontList = nullptr;
565 delete pSVData->maGDIData.mpScreenFontCache;
566 pSVData->maGDIData.mpScreenFontCache = nullptr;
568 pSVData->mpResMgr.reset();
570 ResMgr::DestroyAllResMgr();
572 // destroy all Sal interfaces before destroying the instance
573 // and thereby unloading the plugin
574 delete pSVData->mpSalSystem;
575 pSVData->mpSalSystem = nullptr;
576 delete pSVData->mpSalTimer;
577 pSVData->mpSalTimer = nullptr;
579 // Deinit Sal
580 if (pSVData->mpDefInst)
582 DestroySalInstance( pSVData->mpDefInst );
583 pSVData->mpDefInst = nullptr;
586 if( pOwnSvApp )
588 delete pOwnSvApp;
589 pOwnSvApp = nullptr;
592 EmbeddedFontsHelper::clearTemporaryFontFiles();
595 // only one call is allowed
596 struct WorkerThreadData
598 oslWorkerFunction pWorker;
599 void * pThreadData;
600 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
601 : pWorker( pWorker_ )
602 , pThreadData( pThreadData_ )
607 #ifdef _WIN32
608 static HANDLE hThreadID = nullptr;
609 static unsigned __stdcall threadmain( void *pArgs )
611 OleInitialize( nullptr );
612 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
613 delete static_cast<WorkerThreadData*>(pArgs);
614 OleUninitialize();
615 hThreadID = nullptr;
616 return 0;
618 #else
619 static oslThread hThreadID = nullptr;
620 extern "C"
622 static void SAL_CALL MainWorkerFunction( void* pArgs )
624 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
625 delete static_cast<WorkerThreadData*>(pArgs);
626 hThreadID = nullptr;
628 } // extern "C"
629 #endif
631 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
633 #ifdef _WIN32
634 // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
636 unsigned uThreadID;
637 hThreadID = reinterpret_cast<HANDLE>(_beginthreadex(
638 nullptr, // no security handle
639 0, // stacksize 0 means default
640 threadmain, // thread worker function
641 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
642 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
643 &uThreadID )); // thread id to fill
644 #else
645 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
646 #endif
649 void JoinMainLoopThread()
651 if( hThreadID )
653 #ifdef _WIN32
654 WaitForSingleObject(hThreadID, INFINITE);
655 #else
656 osl_joinWithThread(hThreadID);
657 osl_destroyThread( hThreadID );
658 #endif
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */