Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / app / svmain.cxx
blob2d7950a8aa11337589c06f048162072fe09d2b08
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/vclmain.hxx>
38 #include <vcl/wrkwin.hxx>
39 #include <vcl/cvtgrf.hxx>
40 #include <vcl/scheduler.hxx>
41 #include <vcl/image.hxx>
42 #include <vcl/ImageTree.hxx>
43 #include <vcl/settings.hxx>
44 #include <vcl/unowrap.hxx>
45 #include <vcl/commandinfoprovider.hxx>
46 #include <vcl/configsettings.hxx>
47 #include <vcl/lazydelete.hxx>
48 #include <vcl/embeddedfontshelper.hxx>
49 #include <vcl/debugevent.hxx>
50 #include <vcl/dialog.hxx>
51 #include <vcl/menu.hxx>
52 #include <vcl/virdev.hxx>
53 #include <vcl/print.hxx>
54 #include <scrwnd.hxx>
56 #ifdef _WIN32
57 #include <svsys.h>
58 #include <process.h>
59 #include <ole2.h>
60 #else
61 #include <stdlib.h>
62 #endif
64 #ifdef ANDROID
65 #include <cppuhelper/bootstrap.hxx>
66 #include <jni.h>
67 #endif
69 #include "salinst.hxx"
70 #include "salwtype.hxx"
71 #include "svdata.hxx"
72 #include <vcl/svmain.hxx>
73 #include "dbggui.hxx"
74 #include "accmgr.hxx"
75 #include "outdev.h"
76 #include "fontinstance.hxx"
77 #include "PhysicalFontCollection.hxx"
78 #include "print.h"
79 #include "salgdi.hxx"
80 #include "salsys.hxx"
81 #include "saltimer.hxx"
82 #include "salimestatus.hxx"
83 #include "displayconnectiondispatch.hxx"
85 #include <config_features.h>
86 #if HAVE_FEATURE_OPENGL
87 #include <vcl/opengl/OpenGLContext.hxx>
88 #endif
90 #include <osl/process.h>
91 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
92 #include <com/sun/star/lang/XComponent.hpp>
93 #include <com/sun/star/frame/Desktop.hpp>
95 #include <comphelper/lok.hxx>
96 #include <cppuhelper/implbase.hxx>
97 #include <uno/current_context.hxx>
99 #include <opencl/OpenCLZone.hxx>
100 #include <opengl/zone.hxx>
101 #include <opengl/watchdog.hxx>
103 #if OSL_DEBUG_LEVEL > 0
104 #include <typeinfo>
105 #include <rtl/strbuf.hxx>
106 #endif
108 using namespace ::com::sun::star;
110 static bool g_bIsLeanException;
112 static bool isInitVCL();
114 oslSignalAction SAL_CALL VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
116 static volatile bool bIn = false;
118 // if we crash again, bail out immediately
119 if ( bIn || g_bIsLeanException)
120 return osl_Signal_ActCallNextHdl;
122 ExceptionCategory nVCLException = ExceptionCategory::NONE;
124 // UAE
125 if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
126 (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
127 (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
128 (pInfo->Signal == osl_Signal_DebugBreak) )
130 nVCLException = ExceptionCategory::System;
131 #if HAVE_FEATURE_OPENGL
132 if (OpenGLZone::isInZone())
133 OpenGLZone::hardDisable();
134 #endif
135 #if HAVE_FEATURE_OPENCL
136 if (OpenCLZone::isInZone())
138 OpenCLZone::hardDisable();
139 #ifdef _WIN32
140 if (OpenCLZone::isInInitialTest())
141 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART);
142 #endif
144 #endif
147 // RC
148 if ((pInfo->Signal == osl_Signal_User) &&
149 (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
150 nVCLException = ExceptionCategory::ResourceNotLoaded;
152 // DISPLAY-Unix
153 if ((pInfo->Signal == osl_Signal_User) &&
154 (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
155 nVCLException = ExceptionCategory::UserInterface;
157 if ( nVCLException != ExceptionCategory::NONE )
159 bIn = true;
161 SolarMutexGuard aLock;
163 // do not stop timer because otherwise the UAE-Box will not be painted as well
164 ImplSVData* pSVData = ImplGetSVData();
165 if ( pSVData->mpApp )
167 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
168 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
169 pSVData->mpApp->Exception( nVCLException );
170 Application::SetSystemWindowMode( nOldMode );
172 bIn = false;
175 return osl_Signal_ActCallNextHdl;
179 int ImplSVMain()
181 // The 'real' SVMain()
182 ImplSVData* pSVData = ImplGetSVData();
184 SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" );
186 int nReturn = EXIT_FAILURE;
188 bool bInit = isInitVCL() || InitVCL();
190 if( bInit )
192 // call application main
193 pSVData->maAppData.mbInAppMain = true;
194 nReturn = pSVData->mpApp->Main();
195 pSVData->maAppData.mbInAppMain = false;
198 if( pSVData->mxDisplayConnection.is() )
200 pSVData->mxDisplayConnection->terminate();
201 pSVData->mxDisplayConnection.clear();
204 // This is a hack to work around the problem of the asynchronous nature
205 // of bridging accessibility through Java: on shutdown there might still
206 // be some events in the AWT EventQueue, which need the SolarMutex which
207 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
208 // here ..
209 if( pSVData->mxAccessBridge.is() )
212 SolarMutexReleaser aReleaser;
213 pSVData->mxAccessBridge->dispose();
215 pSVData->mxAccessBridge.clear();
218 #if HAVE_FEATURE_OPENGL
219 OpenGLWatchdogThread::stop();
220 #endif
221 DeInitVCL();
223 return nReturn;
226 int SVMain()
228 int nRet;
229 if( !Application::IsConsoleOnly() && ImplSVMainHook( &nRet ) )
230 return nRet;
231 else
232 return ImplSVMain();
235 // This variable is set when no Application object has been instantiated
236 // before InitVCL is called
237 static Application * pOwnSvApp = nullptr;
239 // Exception handler. pExceptionHandler != NULL => VCL already inited
240 static oslSignalHandler pExceptionHandler = nullptr;
242 class DesktopEnvironmentContext: public cppu::WeakImplHelper< css::uno::XCurrentContext >
244 public:
245 explicit DesktopEnvironmentContext( const css::uno::Reference< css::uno::XCurrentContext > & ctx)
246 : m_xNextContext( ctx ) {}
248 // XCurrentContext
249 virtual css::uno::Any SAL_CALL getValueByName( const OUString& Name ) override;
251 private:
252 css::uno::Reference< css::uno::XCurrentContext > m_xNextContext;
255 uno::Any SAL_CALL DesktopEnvironmentContext::getValueByName( const OUString& Name)
257 uno::Any retVal;
259 if ( Name == "system.desktop-environment" )
261 retVal <<= Application::GetDesktopEnvironment();
263 else if( m_xNextContext.is() )
265 // Call next context in chain if found
266 retVal = m_xNextContext->getValueByName( Name );
268 return retVal;
271 static bool isInitVCL()
273 ImplSVData* pSVData = ImplGetSVData();
274 return pExceptionHandler != nullptr &&
275 pSVData->mpApp != nullptr &&
276 pSVData->mpDefInst != nullptr;
279 #ifdef DBG_UTIL
280 namespace vclmain
282 bool isAlive()
284 return ImplGetSVData()->mpDefInst;
287 #endif
290 bool InitVCL()
292 if( pExceptionHandler != nullptr )
293 return false;
295 EmbeddedFontsHelper::clearTemporaryFontFiles();
297 if( !ImplGetSVData()->mpApp )
299 pOwnSvApp = new Application();
301 InitSalMain();
303 ImplSVData* pSVData = ImplGetSVData();
305 // remember Main-Thread-Id
306 pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
308 // Initialize Sal
309 pSVData->mpDefInst = CreateSalInstance();
310 if ( !pSVData->mpDefInst )
311 return false;
313 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
314 css::uno::setCurrentContext(
315 new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
317 // Initialize application instance (should be done after initialization of VCL SAL part)
318 if( pSVData->mpApp )
319 // call init to initialize application class
320 // soffice/sfx implementation creates the global service manager
321 pSVData->mpApp->Init();
323 pSVData->mpDefInst->AfterAppInit();
325 // Fetch AppFileName and make it absolute before the workdir changes...
326 OUString aExeFileName;
327 osl_getExecutableFile( &aExeFileName.pData );
329 // convert path to native file format
330 OUString aNativeFileName;
331 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
332 pSVData->maAppData.mpAppFileName = new OUString( aNativeFileName );
334 // Initialize global data
335 pSVData->maGDIData.mpScreenFontList = new PhysicalFontCollection;
336 pSVData->maGDIData.mpScreenFontCache = new ImplFontCache;
337 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
339 g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr;
340 // Set exception handler
341 pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr);
343 #ifdef DBG_UTIL
344 DbgGUIInitSolarMutexCheck();
345 #endif
347 #if OSL_DEBUG_LEVEL > 0
348 DebugEventInjector::getCreate();
349 #endif
351 #ifndef _WIN32
352 // Clear startup notification details for child processes
353 // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
354 unsetenv("DESKTOP_STARTUP_ID");
355 #endif
357 return true;
360 namespace
363 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
364 crash at exit in some special cases when a11y is enabled (e.g., when
365 a bundled extension is registered/deregistered during startup, forcing exit
366 while the app is still in splash screen.)
368 class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener>
370 virtual void SAL_CALL disposing(lang::EventObject const& rSource) override;
373 void
374 VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
376 ImplSVData* const pSVData = ImplGetSVData();
377 if (pSVData && pSVData->mpUnoWrapper)
379 pSVData->mpUnoWrapper->Destroy();
380 pSVData->mpUnoWrapper = nullptr;
386 void DeInitVCL()
388 //rhbz#1444437, when using LibreOffice like a library you can't realistically
389 //tear everything down and recreate them on the next call, there's too many
390 //(c++) singletons that point to stuff that gets deleted during shutdown
391 //which won't be recreated on restart.
392 if (comphelper::LibreOfficeKit::isActive())
393 return;
396 SolarMutexReleaser r; // unblock threads blocked on that so we can join
397 ::comphelper::JoinAsyncEventNotifiers();
399 ImplSVData* pSVData = ImplGetSVData();
401 // lp#1560328: clear cache before disposing rest of VCL
402 if(pSVData->mpBlendFrameCache)
403 pSVData->mpBlendFrameCache->m_aLastResult.Clear();
404 pSVData->mbDeInit = true;
406 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
408 // give ime status a chance to destroy its own windows
409 delete pSVData->mpImeStatus;
410 pSVData->mpImeStatus = nullptr;
412 #if OSL_DEBUG_LEVEL > 0
413 OStringBuffer aBuf( 256 );
414 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
415 long nTopWindowCount = Application::GetTopWindowCount();
416 long nBadTopWindows = nTopWindowCount;
417 for( long i = 0; i < nTopWindowCount; i++ )
419 vcl::Window* pWin = Application::GetTopWindow( i );
420 // default window will be destroyed further down
421 // but may still be useful during deinit up to that point
422 if( pWin == pSVData->mpDefaultWin )
423 nBadTopWindows--;
424 else
426 aBuf.append( "text = \"" );
427 aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
428 aBuf.append( "\" type = \"" );
429 aBuf.append( typeid(*pWin).name() );
430 aBuf.append( "\", ptr = 0x" );
431 aBuf.append( sal_Int64( pWin ), 16 );
432 aBuf.append( "\n" );
435 SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
436 #endif
438 ImageTree::get().shutdown();
440 osl_removeSignalHandler( pExceptionHandler);
441 pExceptionHandler = nullptr;
443 // free global data
444 delete pSVData->maGDIData.mpGrfConverter;
446 if( pSVData->mpSettingsConfigItem )
448 delete pSVData->mpSettingsConfigItem;
449 pSVData->mpSettingsConfigItem = nullptr;
452 Scheduler::ImplDeInitScheduler();
454 pSVData->maWinData.maMsgBoxImgList.clear();
455 pSVData->maCtrlData.maCheckImgList.clear();
456 pSVData->maCtrlData.maRadioImgList.clear();
457 if ( pSVData->maCtrlData.mpDisclosurePlus )
459 delete pSVData->maCtrlData.mpDisclosurePlus;
460 pSVData->maCtrlData.mpDisclosurePlus = nullptr;
462 if ( pSVData->maCtrlData.mpDisclosureMinus )
464 delete pSVData->maCtrlData.mpDisclosureMinus;
465 pSVData->maCtrlData.mpDisclosureMinus = nullptr;
467 pSVData->mpDefaultWin.disposeAndClear();
469 #ifdef DBG_UTIL
470 DbgGUIDeInitSolarMutexCheck();
471 #endif
473 if ( pSVData->mpUnoWrapper )
477 uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
478 comphelper::getProcessComponentContext() );
479 xDesktop->addEventListener(new VCLUnoWrapperDeleter);
481 catch (uno::Exception const&)
483 // ignore
487 if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
489 SolarMutexReleaser aReleaser;
490 // call deinit to deinitialize application class
491 // soffice/sfx implementation disposes the global service manager
492 // Warning: After this call you can't call uno services
493 if( pSVData->mpApp )
495 pSVData->mpApp->DeInit();
497 if( pSVData->maDeInitHook.IsSet() )
499 pSVData->maDeInitHook.Call(nullptr);
503 if ( pSVData->maAppData.mpSettings )
505 if ( pSVData->maAppData.mpCfgListener )
507 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
508 delete pSVData->maAppData.mpCfgListener;
511 delete pSVData->maAppData.mpSettings;
512 pSVData->maAppData.mpSettings = nullptr;
514 if ( pSVData->maAppData.mpAccelMgr )
516 delete pSVData->maAppData.mpAccelMgr;
517 pSVData->maAppData.mpAccelMgr = nullptr;
519 if ( pSVData->maAppData.mpAppFileName )
521 delete pSVData->maAppData.mpAppFileName;
522 pSVData->maAppData.mpAppFileName = nullptr;
524 if ( pSVData->maAppData.mpAppName )
526 delete pSVData->maAppData.mpAppName;
527 pSVData->maAppData.mpAppName = nullptr;
529 if ( pSVData->maAppData.mpDisplayName )
531 delete pSVData->maAppData.mpDisplayName;
532 pSVData->maAppData.mpDisplayName = nullptr;
534 if ( pSVData->maAppData.mpToolkitName )
536 delete pSVData->maAppData.mpToolkitName;
537 pSVData->maAppData.mpToolkitName = nullptr;
539 if ( pSVData->maAppData.mpEventListeners )
541 delete pSVData->maAppData.mpEventListeners;
542 pSVData->maAppData.mpEventListeners = nullptr;
544 if ( pSVData->maAppData.mpKeyListeners )
546 delete pSVData->maAppData.mpKeyListeners;
547 pSVData->maAppData.mpKeyListeners = nullptr;
550 if ( pSVData->maAppData.mpFirstHotKey )
551 ImplFreeHotKeyData();
552 if ( pSVData->maAppData.mpFirstEventHook )
553 ImplFreeEventHookData();
555 if (pSVData->mpBlendFrameCache)
557 delete pSVData->mpBlendFrameCache;
558 pSVData->mpBlendFrameCache = nullptr;
561 ImplDeletePrnQueueList();
562 delete pSVData->maGDIData.mpScreenFontList;
563 pSVData->maGDIData.mpScreenFontList = nullptr;
564 delete pSVData->maGDIData.mpScreenFontCache;
565 pSVData->maGDIData.mpScreenFontCache = nullptr;
567 if ( pSVData->mpResMgr )
569 delete pSVData->mpResMgr;
570 pSVData->mpResMgr = nullptr;
573 ResMgr::DestroyAllResMgr();
575 // destroy all Sal interfaces before destroying the instance
576 // and thereby unloading the plugin
577 delete pSVData->mpSalSystem;
578 pSVData->mpSalSystem = nullptr;
579 delete pSVData->mpSalTimer;
580 pSVData->mpSalTimer = nullptr;
582 pSVData->mpDefaultWin = nullptr;
583 pSVData->mpIntroWindow = nullptr;
584 pSVData->maAppData.mpActivePopupMenu = nullptr;
585 pSVData->maAppData.mpWheelWindow = nullptr;
586 pSVData->maGDIData.mpFirstWinGraphics = nullptr;
587 pSVData->maGDIData.mpLastWinGraphics = nullptr;
588 pSVData->maGDIData.mpFirstVirGraphics = nullptr;
589 pSVData->maGDIData.mpLastVirGraphics = nullptr;
590 pSVData->maGDIData.mpFirstPrnGraphics = nullptr;
591 pSVData->maGDIData.mpLastPrnGraphics = nullptr;
592 pSVData->maGDIData.mpFirstVirDev = nullptr;
593 pSVData->maGDIData.mpLastVirDev = nullptr;
594 pSVData->maGDIData.mpFirstPrinter = nullptr;
595 pSVData->maGDIData.mpLastPrinter = nullptr;
596 pSVData->maWinData.mpFirstFrame = nullptr;
597 pSVData->maWinData.mpAppWin = nullptr;
598 pSVData->maWinData.mpActiveApplicationFrame = nullptr;
599 pSVData->maWinData.mpCaptureWin = nullptr;
600 pSVData->maWinData.mpLastDeacWin = nullptr;
601 pSVData->maWinData.mpFirstFloat = nullptr;
602 pSVData->maWinData.mpLastExecuteDlg = nullptr;
603 pSVData->maWinData.mpExtTextInputWin = nullptr;
604 pSVData->maWinData.mpTrackWin = nullptr;
605 pSVData->maWinData.mpAutoScrollWin = nullptr;
606 pSVData->maWinData.mpLastWheelWindow = nullptr;
607 // Deinit Sal
608 if (pSVData->mpDefInst)
610 DestroySalInstance( pSVData->mpDefInst );
611 pSVData->mpDefInst = nullptr;
614 if( pOwnSvApp )
616 delete pOwnSvApp;
617 pOwnSvApp = nullptr;
620 EmbeddedFontsHelper::clearTemporaryFontFiles();
623 // only one call is allowed
624 struct WorkerThreadData
626 oslWorkerFunction pWorker;
627 void * pThreadData;
628 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
629 : pWorker( pWorker_ )
630 , pThreadData( pThreadData_ )
635 #ifdef _WIN32
636 static HANDLE hThreadID = nullptr;
637 static unsigned __stdcall threadmain( void *pArgs )
639 OleInitialize( nullptr );
640 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
641 delete static_cast<WorkerThreadData*>(pArgs);
642 OleUninitialize();
643 hThreadID = nullptr;
644 return 0;
646 #else
647 static oslThread hThreadID = nullptr;
648 extern "C"
650 static void SAL_CALL MainWorkerFunction( void* pArgs )
652 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
653 delete static_cast<WorkerThreadData*>(pArgs);
654 hThreadID = nullptr;
656 } // extern "C"
657 #endif
659 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
661 #ifdef _WIN32
662 // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
664 unsigned uThreadID;
665 hThreadID = reinterpret_cast<HANDLE>(_beginthreadex(
666 nullptr, // no security handle
667 0, // stacksize 0 means default
668 threadmain, // thread worker function
669 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
670 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
671 &uThreadID )); // thread id to fill
672 #else
673 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
674 #endif
677 void JoinMainLoopThread()
679 if( hThreadID )
681 #ifdef _WIN32
682 WaitForSingleObject(hThreadID, INFINITE);
683 #else
684 osl_joinWithThread(hThreadID);
685 osl_destroyThread( hThreadID );
686 #endif
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */