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>
21 #include <sal/log.hxx>
25 #include <osl/file.hxx>
26 #include <osl/signal.h>
28 #include <desktop/exithelper.h>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/asyncnotification.hxx>
32 #include <i18nlangtag/mslangid.hxx>
33 #include <unotools/syslocaleoptions.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/vclmain.hxx>
36 #include <vcl/wrkwin.hxx>
37 #include <vcl/cvtgrf.hxx>
38 #include <vcl/scheduler.hxx>
39 #include <vcl/image.hxx>
40 #include <vcl/ImageTree.hxx>
41 #include <vcl/settings.hxx>
42 #include <vcl/toolkit/unowrap.hxx>
43 #include <vcl/configsettings.hxx>
44 #include <vcl/lazydelete.hxx>
45 #include <vcl/embeddedfontshelper.hxx>
46 #include <vcl/debugevent.hxx>
47 #include <vcl/dialog.hxx>
48 #include <vcl/menu.hxx>
49 #include <vcl/virdev.hxx>
50 #include <vcl/print.hxx>
62 #include <cppuhelper/bootstrap.hxx>
66 #include <impfontcache.hxx>
67 #include <salinst.hxx>
69 #include <vcl/svmain.hxx>
72 #include <PhysicalFontCollection.hxx>
75 #include <saltimer.hxx>
76 #include <displayconnectiondispatch.hxx>
78 #include <config_features.h>
79 #include <config_feature_opencl.h>
81 #include <osl/process.h>
82 #include <com/sun/star/lang/XComponent.hpp>
83 #include <com/sun/star/frame/Desktop.hpp>
85 #include <comphelper/lok.hxx>
86 #include <cppuhelper/implbase.hxx>
87 #include <uno/current_context.hxx>
89 #include <opencl/OpenCLZone.hxx>
90 #include <opengl/zone.hxx>
91 #include <opengl/watchdog.hxx>
93 #include <basegfx/utils/systemdependentdata.hxx>
94 #include <tools/diagnose_ex.h>
96 #if OSL_DEBUG_LEVEL > 0
98 #include <rtl/strbuf.hxx>
101 using namespace ::com::sun::star
;
103 static bool g_bIsLeanException
;
105 static oslSignalAction
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
;
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();
126 #if HAVE_FEATURE_OPENCL
127 if (OpenCLZone::isInZone())
129 OpenCLZone::hardDisable();
131 if (OpenCLZone::isInInitialTest())
132 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART
);
139 if ((pInfo
->Signal
== osl_Signal_User
) &&
140 (pInfo
->UserSignal
== OSL_SIGNAL_USER_RESOURCEFAILURE
) )
141 nVCLException
= ExceptionCategory::ResourceNotLoaded
;
144 if ((pInfo
->Signal
== osl_Signal_User
) &&
145 (pInfo
->UserSignal
== OSL_SIGNAL_USER_X11SUBSYSTEMERROR
) )
146 nVCLException
= ExceptionCategory::UserInterface
;
148 if ( nVCLException
!= ExceptionCategory::NONE
)
152 vcl::SolarMutexTryAndBuyGuard aLock
;
153 if( aLock
.isAcquired())
155 // do not stop timer because otherwise the UAE-Box will not be painted as well
156 ImplSVData
* pSVData
= ImplGetSVData();
157 if ( pSVData
->mpApp
)
159 SystemWindowFlags nOldMode
= Application::GetSystemWindowMode();
160 Application::SetSystemWindowMode( nOldMode
& ~SystemWindowFlags::NOAUTOMODE
);
161 pSVData
->mpApp
->Exception( nVCLException
);
162 Application::SetSystemWindowMode( nOldMode
);
168 return osl_Signal_ActCallNextHdl
;
174 // The 'real' SVMain()
175 ImplSVData
* pSVData
= ImplGetSVData();
177 SAL_WARN_IF( !pSVData
->mpApp
, "vcl", "no instance of class Application" );
179 int nReturn
= EXIT_FAILURE
;
181 const bool bWasInitVCL
= IsVCLInit();
182 const bool bInit
= bWasInitVCL
|| InitVCL();
184 if (!bWasInitVCL
&& bInit
&& pSVData
->mpDefInst
->SVMainHook(&nRet
))
189 // call application main
190 pSVData
->maAppData
.mbInAppMain
= true;
191 nReturn
= pSVData
->mpApp
->Main();
192 pSVData
->maAppData
.mbInAppMain
= false;
195 if( pSVData
->mxDisplayConnection
.is() )
197 pSVData
->mxDisplayConnection
->terminate();
198 pSVData
->mxDisplayConnection
.clear();
201 // This is a hack to work around the problem of the asynchronous nature
202 // of bridging accessibility through Java: on shutdown there might still
203 // be some events in the AWT EventQueue, which need the SolarMutex which
204 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
206 if( pSVData
->mxAccessBridge
.is() )
209 SolarMutexReleaser aReleaser
;
210 pSVData
->mxAccessBridge
->dispose();
212 pSVData
->mxAccessBridge
.clear();
215 #if HAVE_FEATURE_OPENGL
216 OpenGLWatchdogThread::stop();
228 // This variable is set when no Application object has been instantiated
229 // before InitVCL is called
230 static Application
* pOwnSvApp
= nullptr;
232 // Exception handler. pExceptionHandler != NULL => VCL already inited
233 static oslSignalHandler pExceptionHandler
= nullptr;
235 class DesktopEnvironmentContext
: public cppu::WeakImplHelper
< css::uno::XCurrentContext
>
238 explicit DesktopEnvironmentContext( const css::uno::Reference
< css::uno::XCurrentContext
> & ctx
)
239 : m_xNextContext( ctx
) {}
242 virtual css::uno::Any SAL_CALL
getValueByName( const OUString
& Name
) override
;
245 css::uno::Reference
< css::uno::XCurrentContext
> m_xNextContext
;
248 uno::Any SAL_CALL
DesktopEnvironmentContext::getValueByName( const OUString
& Name
)
252 if ( Name
== "system.desktop-environment" )
254 retVal
<<= Application::GetDesktopEnvironment();
256 else if( m_xNextContext
.is() )
258 // Call next context in chain if found
259 retVal
= m_xNextContext
->getValueByName( Name
);
266 ImplSVData
* pSVData
= ImplGetSVData();
267 return pExceptionHandler
!= nullptr &&
268 pSVData
->mpApp
!= nullptr &&
269 pSVData
->mpDefInst
!= nullptr;
277 return ImplGetSVData()->mpDefInst
;
287 SAL_INFO("vcl.app", "Double initialization of vcl");
291 if( pExceptionHandler
!= nullptr )
294 EmbeddedFontsHelper::clearTemporaryFontFiles();
296 if( !ImplGetSVData()->mpApp
)
298 pOwnSvApp
= new Application();
301 ImplSVData
* pSVData
= ImplGetSVData();
303 // remember Main-Thread-Id
304 pSVData
->mnMainThreadId
= ::osl::Thread::getCurrentIdentifier();
307 pSVData
->mpDefInst
= CreateSalInstance();
308 if ( !pSVData
->mpDefInst
)
311 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
312 css::uno::setCurrentContext(
313 new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
315 // Initialize application instance (should be done after initialization of VCL SAL part)
318 // call init to initialize application class
319 // soffice/sfx implementation creates the global service manager
320 pSVData
->mpApp
->Init();
325 //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can
326 //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL
327 //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python)
328 //to match their translations to our preferred UI language
329 OUString
aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(".UTF-8"));
330 if (!aLocaleString
.isEmpty())
332 MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was
333 OUString
envVar("LANGUAGE");
334 osl_setEnvironment(envVar
.pData
, aLocaleString
.pData
);
337 catch (const uno::Exception
&)
339 TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:");
342 pSVData
->mpDefInst
->AfterAppInit();
344 // Fetch AppFileName and make it absolute before the workdir changes...
345 OUString aExeFileName
;
346 osl_getExecutableFile( &aExeFileName
.pData
);
348 // convert path to native file format
349 OUString aNativeFileName
;
350 osl::FileBase::getSystemPathFromFileURL( aExeFileName
, aNativeFileName
);
351 pSVData
->maAppData
.mxAppFileName
= aNativeFileName
;
353 // Initialize global data
354 pSVData
->maGDIData
.mxScreenFontList
.reset(new PhysicalFontCollection
);
355 pSVData
->maGDIData
.mxScreenFontCache
.reset(new ImplFontCache
);
356 pSVData
->maGDIData
.mpGrfConverter
= new GraphicConverter
;
358 g_bIsLeanException
= getenv("LO_LEAN_EXCEPTION") != nullptr;
359 // Set exception handler
360 pExceptionHandler
= osl_addSignalHandler(VCLExceptionSignal_impl
, nullptr);
363 DbgGUIInitSolarMutexCheck();
366 #if OSL_DEBUG_LEVEL > 0
367 DebugEventInjector::getCreate();
371 // Clear startup notification details for child processes
372 // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
373 unsetenv("DESKTOP_STARTUP_ID");
382 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
383 crash at exit in some special cases when a11y is enabled (e.g., when
384 a bundled extension is registered/deregistered during startup, forcing exit
385 while the app is still in splash screen.)
387 class VCLUnoWrapperDeleter
: public cppu::WeakImplHelper
<css::lang::XEventListener
>
389 virtual void SAL_CALL
disposing(lang::EventObject
const& rSource
) override
;
393 VCLUnoWrapperDeleter::disposing(lang::EventObject
const& /* rSource */)
395 ImplSVData
* const pSVData
= ImplGetSVData();
396 if (pSVData
&& pSVData
->mpUnoWrapper
)
398 pSVData
->mpUnoWrapper
->Destroy();
399 pSVData
->mpUnoWrapper
= nullptr;
407 //rhbz#1444437, when using LibreOffice like a library you can't realistically
408 //tear everything down and recreate them on the next call, there's too many
409 //(c++) singletons that point to stuff that gets deleted during shutdown
410 //which won't be recreated on restart.
411 if (comphelper::LibreOfficeKit::isActive())
415 SolarMutexReleaser r
; // unblock threads blocked on that so we can join
416 ::comphelper::JoinAsyncEventNotifiers();
418 ImplSVData
* pSVData
= ImplGetSVData();
420 // lp#1560328: clear cache before disposing rest of VCL
421 if(pSVData
->mpBlendFrameCache
)
422 pSVData
->mpBlendFrameCache
->m_aLastResult
.Clear();
423 pSVData
->mbDeInit
= true;
425 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
427 #if OSL_DEBUG_LEVEL > 0
428 OStringBuffer
aBuf( 256 );
429 aBuf
.append( "DeInitVCL: some top Windows are still alive\n" );
430 long nTopWindowCount
= Application::GetTopWindowCount();
431 long nBadTopWindows
= nTopWindowCount
;
432 for( long i
= 0; i
< nTopWindowCount
; i
++ )
434 vcl::Window
* pWin
= Application::GetTopWindow( i
);
435 // default window will be destroyed further down
436 // but may still be useful during deinit up to that point
437 if( pWin
== pSVData
->mpDefaultWin
)
441 aBuf
.append( "text = \"" );
442 aBuf
.append( OUStringToOString( pWin
->GetText(), osl_getThreadTextEncoding() ) );
443 aBuf
.append( "\" type = \"" );
444 aBuf
.append( typeid(*pWin
).name() );
445 aBuf
.append( "\", ptr = 0x" );
446 aBuf
.append( sal_Int64( pWin
), 16 );
450 SAL_WARN_IF( nBadTopWindows
!=0, "vcl", aBuf
.getStr() );
453 ImageTree::get().shutdown();
455 osl_removeSignalHandler( pExceptionHandler
);
456 pExceptionHandler
= nullptr;
459 if (pSVData
->maGDIData
.mpGrfConverter
)
461 delete pSVData
->maGDIData
.mpGrfConverter
;
462 pSVData
->maGDIData
.mpGrfConverter
= nullptr;
465 pSVData
->mpSettingsConfigItem
.reset();
467 // prevent unnecessary painting during Scheduler shutdown
468 // as this processes all pending events in debug builds.
469 ImplGetSystemDependentDataManager().flushAll();
471 Scheduler::ImplDeInitScheduler();
473 pSVData
->maWinData
.maMsgBoxImgList
.clear();
474 pSVData
->maCtrlData
.maCheckImgList
.clear();
475 pSVData
->maCtrlData
.maRadioImgList
.clear();
476 pSVData
->maCtrlData
.mpDisclosurePlus
.reset();
477 pSVData
->maCtrlData
.mpDisclosureMinus
.reset();
478 pSVData
->mpDefaultWin
.disposeAndClear();
481 DbgGUIDeInitSolarMutexCheck();
484 if ( pSVData
->mpUnoWrapper
)
488 uno::Reference
<frame::XDesktop2
> const xDesktop
= frame::Desktop::create(
489 comphelper::getProcessComponentContext() );
490 xDesktop
->addEventListener(new VCLUnoWrapperDeleter
);
492 catch (uno::Exception
const&)
498 if( pSVData
->mpApp
|| pSVData
->maDeInitHook
.IsSet() )
500 SolarMutexReleaser aReleaser
;
501 // call deinit to deinitialize application class
502 // soffice/sfx implementation disposes the global service manager
503 // Warning: After this call you can't call uno services
506 pSVData
->mpApp
->DeInit();
508 if( pSVData
->maDeInitHook
.IsSet() )
510 pSVData
->maDeInitHook
.Call(nullptr);
514 if ( pSVData
->maAppData
.mpSettings
)
516 if ( pSVData
->maAppData
.mpCfgListener
)
518 pSVData
->maAppData
.mpSettings
->GetSysLocale().GetOptions().RemoveListener( pSVData
->maAppData
.mpCfgListener
);
519 delete pSVData
->maAppData
.mpCfgListener
;
522 pSVData
->maAppData
.mpSettings
.reset();
524 if (pSVData
->maAppData
.mpAccelMgr
)
526 delete pSVData
->maAppData
.mpAccelMgr
;
527 pSVData
->maAppData
.mpAccelMgr
= nullptr;
529 pSVData
->maAppData
.maKeyListeners
.clear();
530 pSVData
->mpBlendFrameCache
.reset();
532 ImplDeletePrnQueueList();
534 // destroy all Sal interfaces before destroying the instance
535 // and thereby unloading the plugin
536 pSVData
->mpSalSystem
.reset();
537 assert( !pSVData
->maSchedCtx
.mpSalTimer
);
538 delete pSVData
->maSchedCtx
.mpSalTimer
;
539 pSVData
->maSchedCtx
.mpSalTimer
= nullptr;
541 pSVData
->mpDefaultWin
= nullptr;
542 pSVData
->mpIntroWindow
= nullptr;
543 pSVData
->maAppData
.mpActivePopupMenu
= nullptr;
544 pSVData
->maAppData
.mpWheelWindow
= nullptr;
545 pSVData
->maGDIData
.mpFirstWinGraphics
= nullptr;
546 pSVData
->maGDIData
.mpLastWinGraphics
= nullptr;
547 pSVData
->maGDIData
.mpFirstVirGraphics
= nullptr;
548 pSVData
->maGDIData
.mpLastVirGraphics
= nullptr;
549 pSVData
->maGDIData
.mpFirstPrnGraphics
= nullptr;
550 pSVData
->maGDIData
.mpLastPrnGraphics
= nullptr;
551 pSVData
->maGDIData
.mpFirstVirDev
= nullptr;
552 pSVData
->maGDIData
.mpFirstPrinter
= nullptr;
553 pSVData
->maWinData
.mpFirstFrame
= nullptr;
554 pSVData
->maWinData
.mpAppWin
= nullptr;
555 pSVData
->maWinData
.mpActiveApplicationFrame
= nullptr;
556 pSVData
->maWinData
.mpCaptureWin
= nullptr;
557 pSVData
->maWinData
.mpLastDeacWin
= nullptr;
558 pSVData
->maWinData
.mpFirstFloat
= nullptr;
559 pSVData
->maWinData
.mpExecuteDialogs
.clear();
560 pSVData
->maWinData
.mpExtTextInputWin
= nullptr;
561 pSVData
->maWinData
.mpTrackWin
= nullptr;
562 pSVData
->maWinData
.mpAutoScrollWin
= nullptr;
563 pSVData
->maWinData
.mpLastWheelWindow
= nullptr;
565 pSVData
->maGDIData
.mxScreenFontList
.reset();
566 pSVData
->maGDIData
.mxScreenFontCache
.reset();
567 pSVData
->maGDIData
.maScaleCache
.remove_if([](const o3tl::lru_map
<SalBitmap
*, BitmapEx
>::key_value_pair_t
&)
570 pSVData
->maGDIData
.maThemeDrawCommandsCache
.clear();
571 pSVData
->maGDIData
.maThemeImageCache
.clear();
574 if (pSVData
->mpDefInst
)
576 DestroySalInstance( pSVData
->mpDefInst
);
577 pSVData
->mpDefInst
= nullptr;
586 EmbeddedFontsHelper::clearTemporaryFontFiles();
589 // only one call is allowed
590 struct WorkerThreadData
592 oslWorkerFunction
const pWorker
;
593 void * const pThreadData
;
594 WorkerThreadData( oslWorkerFunction pWorker_
, void * pThreadData_
)
595 : pWorker( pWorker_
)
596 , pThreadData( pThreadData_
)
602 static HANDLE hThreadID
= nullptr;
603 static unsigned __stdcall
threadmain( void *pArgs
)
605 OleInitialize( nullptr );
606 static_cast<WorkerThreadData
*>(pArgs
)->pWorker( static_cast<WorkerThreadData
*>(pArgs
)->pThreadData
);
607 delete static_cast<WorkerThreadData
*>(pArgs
);
613 static oslThread hThreadID
= nullptr;
616 static void MainWorkerFunction( void* pArgs
)
618 static_cast<WorkerThreadData
*>(pArgs
)->pWorker( static_cast<WorkerThreadData
*>(pArgs
)->pThreadData
);
619 delete static_cast<WorkerThreadData
*>(pArgs
);
625 void CreateMainLoopThread( oslWorkerFunction pWorker
, void * pThreadData
)
628 // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
631 hThreadID
= reinterpret_cast<HANDLE
>(_beginthreadex(
632 nullptr, // no security handle
633 0, // stacksize 0 means default
634 threadmain
, // thread worker function
635 new WorkerThreadData( pWorker
, pThreadData
), // arguments for worker function
636 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
637 &uThreadID
)); // thread id to fill
639 hThreadID
= osl_createThread( MainWorkerFunction
, new WorkerThreadData( pWorker
, pThreadData
) );
643 void JoinMainLoopThread()
648 WaitForSingleObject(hThreadID
, INFINITE
);
650 osl_joinWithThread(hThreadID
);
651 osl_destroyThread( hThreadID
);
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */