1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
65 #include <cppuhelper/bootstrap.hxx>
69 #include "salinst.hxx"
70 #include "salwtype.hxx"
72 #include <vcl/svmain.hxx>
76 #include "fontinstance.hxx"
77 #include "PhysicalFontCollection.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>
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
105 #include <rtl/strbuf.hxx>
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
;
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();
135 #if HAVE_FEATURE_OPENCL
136 if (OpenCLZone::isInZone())
138 OpenCLZone::hardDisable();
140 if (OpenCLZone::isInInitialTest())
141 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART
);
148 if ((pInfo
->Signal
== osl_Signal_User
) &&
149 (pInfo
->UserSignal
== OSL_SIGNAL_USER_RESOURCEFAILURE
) )
150 nVCLException
= ExceptionCategory::ResourceNotLoaded
;
153 if ((pInfo
->Signal
== osl_Signal_User
) &&
154 (pInfo
->UserSignal
== OSL_SIGNAL_USER_X11SUBSYSTEMERROR
) )
155 nVCLException
= ExceptionCategory::UserInterface
;
157 if ( nVCLException
!= ExceptionCategory::NONE
)
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
);
175 return osl_Signal_ActCallNextHdl
;
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();
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
209 if( pSVData
->mxAccessBridge
.is() )
212 SolarMutexReleaser aReleaser
;
213 pSVData
->mxAccessBridge
->dispose();
215 pSVData
->mxAccessBridge
.clear();
218 #if HAVE_FEATURE_OPENGL
219 OpenGLWatchdogThread::stop();
229 if( !Application::IsConsoleOnly() && ImplSVMainHook( &nRet
) )
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
>
245 explicit DesktopEnvironmentContext( const css::uno::Reference
< css::uno::XCurrentContext
> & ctx
)
246 : m_xNextContext( ctx
) {}
249 virtual css::uno::Any SAL_CALL
getValueByName( const OUString
& Name
) override
;
252 css::uno::Reference
< css::uno::XCurrentContext
> m_xNextContext
;
255 uno::Any SAL_CALL
DesktopEnvironmentContext::getValueByName( const OUString
& Name
)
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
);
271 static bool isInitVCL()
273 ImplSVData
* pSVData
= ImplGetSVData();
274 return pExceptionHandler
!= nullptr &&
275 pSVData
->mpApp
!= nullptr &&
276 pSVData
->mpDefInst
!= nullptr;
284 return ImplGetSVData()->mpDefInst
;
292 if( pExceptionHandler
!= nullptr )
295 EmbeddedFontsHelper::clearTemporaryFontFiles();
297 if( !ImplGetSVData()->mpApp
)
299 pOwnSvApp
= new Application();
303 ImplSVData
* pSVData
= ImplGetSVData();
305 // remember Main-Thread-Id
306 pSVData
->mnMainThreadId
= ::osl::Thread::getCurrentIdentifier();
309 pSVData
->mpDefInst
= CreateSalInstance();
310 if ( !pSVData
->mpDefInst
)
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)
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);
344 DbgGUIInitSolarMutexCheck();
347 #if OSL_DEBUG_LEVEL > 0
348 DebugEventInjector::getCreate();
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");
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
;
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;
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())
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
)
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 );
435 SAL_WARN_IF( nBadTopWindows
!=0, "vcl", aBuf
.getStr() );
438 ImageTree::get().shutdown();
440 osl_removeSignalHandler( pExceptionHandler
);
441 pExceptionHandler
= nullptr;
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();
470 DbgGUIDeInitSolarMutexCheck();
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&)
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
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;
608 if (pSVData
->mpDefInst
)
610 DestroySalInstance( pSVData
->mpDefInst
);
611 pSVData
->mpDefInst
= nullptr;
620 EmbeddedFontsHelper::clearTemporaryFontFiles();
623 // only one call is allowed
624 struct WorkerThreadData
626 oslWorkerFunction pWorker
;
628 WorkerThreadData( oslWorkerFunction pWorker_
, void * pThreadData_
)
629 : pWorker( pWorker_
)
630 , pThreadData( pThreadData_
)
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
);
647 static oslThread hThreadID
= nullptr;
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
);
659 void CreateMainLoopThread( oslWorkerFunction pWorker
, void * pThreadData
)
662 // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
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
673 hThreadID
= osl_createThread( MainWorkerFunction
, new WorkerThreadData( pWorker
, pThreadData
) );
677 void JoinMainLoopThread()
682 WaitForSingleObject(hThreadID
, INFINITE
);
684 osl_joinWithThread(hThreadID
);
685 osl_destroyThread( hThreadID
);
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */