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/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>
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>
56 #include <windowdev.hxx>
68 #include <cppuhelper/bootstrap.hxx>
72 #include <impfontcache.hxx>
73 #include <salinst.hxx>
74 #include <vcl/svmain.hxx>
77 #include <font/PhysicalFontCollection.hxx>
80 #include <saltimer.hxx>
81 #include <displayconnectiondispatch.hxx>
83 #include <config_features.h>
84 #include <config_feature_opencl.h>
86 #include <osl/process.h>
87 #include <com/sun/star/lang/XComponent.hpp>
88 #include <com/sun/star/frame/Desktop.hpp>
91 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
94 #include <comphelper/lok.hxx>
95 #include <cppuhelper/implbase.hxx>
96 #include <uno/current_context.hxx>
98 #include <opencl/OpenCLZone.hxx>
99 #include <opengl/zone.hxx>
100 #include <skia/zone.hxx>
101 #include <watchdog.hxx>
103 #include <basegfx/utils/systemdependentdata.hxx>
104 #include <comphelper/diagnose_ex.hxx>
106 #if OSL_DEBUG_LEVEL > 0
108 #include <rtl/strbuf.hxx>
112 #include <unx/gendata.hxx>
115 using namespace ::com::sun::star
;
117 static bool g_bIsLeanException
;
119 static oslSignalAction
VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo
* pInfo
)
121 static volatile bool bIn
= false;
123 // if we crash again, bail out immediately
124 if ( bIn
|| g_bIsLeanException
)
125 return osl_Signal_ActCallNextHdl
;
127 ExceptionCategory nVCLException
= ExceptionCategory::NONE
;
130 if ( (pInfo
->Signal
== osl_Signal_AccessViolation
) ||
131 (pInfo
->Signal
== osl_Signal_IntegerDivideByZero
) ||
132 (pInfo
->Signal
== osl_Signal_FloatDivideByZero
) ||
133 (pInfo
->Signal
== osl_Signal_DebugBreak
) )
135 nVCLException
= ExceptionCategory::System
;
136 #if HAVE_FEATURE_OPENGL
137 if (OpenGLZone::isInZone())
138 OpenGLZone::hardDisable();
140 #if HAVE_FEATURE_SKIA
141 if (SkiaZone::isInZone())
142 SkiaZone::hardDisable();
144 #if HAVE_FEATURE_OPENCL
145 if (OpenCLZone::isInZone())
147 OpenCLZone::hardDisable();
149 if (OpenCLInitialZone::isInZone())
150 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART
);
157 if ((pInfo
->Signal
== osl_Signal_User
) &&
158 (pInfo
->UserSignal
== OSL_SIGNAL_USER_X11SUBSYSTEMERROR
) )
159 nVCLException
= ExceptionCategory::UserInterface
;
161 if ( nVCLException
!= ExceptionCategory::NONE
)
165 vcl::SolarMutexTryAndBuyGuard aLock
;
166 if( aLock
.isAcquired())
168 // do not stop timer because otherwise the UAE-Box will not be painted as well
169 ImplSVData
* pSVData
= ImplGetSVData();
170 if ( pSVData
->mpApp
)
172 SystemWindowFlags nOldMode
= Application::GetSystemWindowMode();
173 Application::SetSystemWindowMode( nOldMode
& ~SystemWindowFlags::NOAUTOMODE
);
174 pSVData
->mpApp
->Exception( nVCLException
);
175 Application::SetSystemWindowMode( nOldMode
);
181 return osl_Signal_ActCallNextHdl
;
187 // The 'real' SVMain()
188 ImplSVData
* pSVData
= ImplGetSVData();
190 SAL_WARN_IF( !pSVData
->mpApp
, "vcl", "no instance of class Application" );
192 int nReturn
= EXIT_FAILURE
;
194 const bool bWasInitVCL
= IsVCLInit();
195 const bool bInit
= bWasInitVCL
|| InitVCL();
197 if (!bWasInitVCL
&& bInit
&& pSVData
->mpDefInst
->SVMainHook(&nRet
))
202 // call application main
203 pSVData
->maAppData
.mbInAppMain
= true;
204 nReturn
= pSVData
->mpApp
->Main();
205 pSVData
->maAppData
.mbInAppMain
= false;
208 if( pSVData
->mxDisplayConnection
.is() )
210 pSVData
->mxDisplayConnection
->terminate();
211 pSVData
->mxDisplayConnection
.clear();
214 // This is a hack to work around the problem of the asynchronous nature
215 // of bridging accessibility through Java: on shutdown there might still
216 // be some events in the AWT EventQueue, which need the SolarMutex which
217 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
219 if( pSVData
->mxAccessBridge
.is() )
222 SolarMutexReleaser aReleaser
;
223 pSVData
->mxAccessBridge
->dispose();
225 pSVData
->mxAccessBridge
.clear();
228 WatchdogThread::stop();
239 // This variable is set when no Application object has been instantiated
240 // before InitVCL is called
241 static Application
* pOwnSvApp
= nullptr;
243 // Exception handler. pExceptionHandler != NULL => VCL already inited
244 static oslSignalHandler pExceptionHandler
= nullptr;
248 class DesktopEnvironmentContext
: public cppu::WeakImplHelper
< css::uno::XCurrentContext
>
251 explicit DesktopEnvironmentContext( css::uno::Reference
< css::uno::XCurrentContext
> ctx
)
252 : m_xNextContext(std::move( ctx
)) {}
255 virtual css::uno::Any SAL_CALL
getValueByName( const OUString
& Name
) override
;
258 css::uno::Reference
< css::uno::XCurrentContext
> m_xNextContext
;
263 uno::Any SAL_CALL
DesktopEnvironmentContext::getValueByName( const OUString
& Name
)
267 if ( Name
== "system.desktop-environment" )
269 retVal
<<= Application::GetDesktopEnvironment();
271 else if( m_xNextContext
.is() )
273 // Call next context in chain if found
274 retVal
= m_xNextContext
->getValueByName( Name
);
281 ImplSVData
* pSVData
= ImplGetSVData();
282 return pExceptionHandler
!= nullptr &&
283 pSVData
->mpApp
!= nullptr &&
284 pSVData
->mpDefInst
!= nullptr;
292 return ImplGetSVData()->mpDefInst
;
302 SAL_INFO("vcl.app", "Double initialization of vcl");
306 if( pExceptionHandler
!= nullptr )
309 EmbeddedFontsHelper::clearTemporaryFontFiles();
311 if( !ImplGetSVData()->mpApp
)
313 pOwnSvApp
= new Application();
316 ImplSVData
* pSVData
= ImplGetSVData();
318 // remember Main-Thread-Id
319 pSVData
->mnMainThreadId
= ::osl::Thread::getCurrentIdentifier();
322 pSVData
->mpDefInst
= CreateSalInstance();
323 if ( !pSVData
->mpDefInst
)
325 pSVData
->mpDefInst
->AcquireYieldMutex();
327 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
328 css::uno::setCurrentContext(
329 new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
331 // Initialize application instance (should be done after initialization of VCL SAL part)
334 // call init to initialize application class
335 // soffice/sfx implementation creates the global service manager
336 pSVData
->mpApp
->Init();
341 //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can
342 //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL
343 //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python)
344 //to match their translations to our preferred UI language
345 OUString
aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(u
".UTF-8"));
346 if (!aLocaleString
.isEmpty())
348 MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was
349 OUString
envVar("LANGUAGE");
350 osl_setEnvironment(envVar
.pData
, aLocaleString
.pData
);
353 catch (const uno::Exception
&)
355 TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:");
358 pSVData
->mpDefInst
->AfterAppInit();
360 // Fetch AppFileName and make it absolute before the workdir changes...
361 OUString aExeFileName
;
362 osl_getExecutableFile( &aExeFileName
.pData
);
364 // convert path to native file format
365 OUString aNativeFileName
;
366 osl::FileBase::getSystemPathFromFileURL( aExeFileName
, aNativeFileName
);
367 pSVData
->maAppData
.mxAppFileName
= aNativeFileName
;
369 // Initialize global data
370 pSVData
->maGDIData
.mxScreenFontList
= std::make_shared
<vcl::font::PhysicalFontCollection
>();
371 pSVData
->maGDIData
.mxScreenFontCache
= std::make_shared
<ImplFontCache
>();
372 pSVData
->maGDIData
.mxGrfConverter
.reset(new GraphicConverter
);
374 g_bIsLeanException
= getenv("LO_LEAN_EXCEPTION") != nullptr;
375 // Set exception handler
376 pExceptionHandler
= osl_addSignalHandler(VCLExceptionSignal_impl
, nullptr);
379 DbgGUIInitSolarMutexCheck();
382 #if OSL_DEBUG_LEVEL > 0
383 DebugEventInjector::getCreate();
387 // Clear startup notification details for child processes
388 // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
389 unsetenv("DESKTOP_STARTUP_ID");
398 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
399 crash at exit in some special cases when a11y is enabled (e.g., when
400 a bundled extension is registered/deregistered during startup, forcing exit
401 while the app is still in splash screen.)
403 class VCLUnoWrapperDeleter
: public cppu::WeakImplHelper
<css::lang::XEventListener
>
405 virtual void SAL_CALL
disposing(lang::EventObject
const& rSource
) override
;
409 VCLUnoWrapperDeleter::disposing(lang::EventObject
const& /* rSource */)
411 ImplSVData
* const pSVData
= ImplGetSVData();
412 if (pSVData
&& pSVData
->mpUnoWrapper
)
414 pSVData
->mpUnoWrapper
->Destroy();
415 pSVData
->mpUnoWrapper
= nullptr;
423 // The LOK Windows map container should be empty
424 assert(vcl::Window::IsLOKWindowsEmpty());
426 //rhbz#1444437, when using LibreOffice like a library you can't realistically
427 //tear everything down and recreate them on the next call, there's too many
428 //(c++) singletons that point to stuff that gets deleted during shutdown
429 //which won't be recreated on restart.
430 if (comphelper::LibreOfficeKit::isActive())
434 SolarMutexReleaser r
; // unblock threads blocked on that so we can join
435 ::comphelper::JoinAsyncEventNotifiers();
437 ImplSVData
* pSVData
= ImplGetSVData();
439 // lp#1560328: clear cache before disposing rest of VCL
440 if(pSVData
->mpBlendFrameCache
)
441 pSVData
->mpBlendFrameCache
->m_aLastResult
.Clear();
442 pSVData
->mbDeInit
= true;
444 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
446 #if OSL_DEBUG_LEVEL > 0
447 OStringBuffer
aBuf( 256 );
448 aBuf
.append( "DeInitVCL: some top Windows are still alive\n" );
449 tools::Long nTopWindowCount
= Application::GetTopWindowCount();
450 tools::Long nBadTopWindows
= nTopWindowCount
;
451 for( tools::Long i
= 0; i
< nTopWindowCount
; i
++ )
453 vcl::Window
* pWin
= Application::GetTopWindow( i
);
454 // default window will be destroyed further down
455 // but may still be useful during deinit up to that point
456 if( pWin
== pSVData
->mpDefaultWin
)
460 aBuf
.append( "text = \""
461 + OUStringToOString( pWin
->GetText(), osl_getThreadTextEncoding() )
463 + typeid(*pWin
).name()
465 + OString::number(reinterpret_cast<sal_Int64
>( pWin
), 16 )
469 SAL_WARN_IF( nBadTopWindows
!=0, "vcl", aBuf
.getStr() );
472 ImageTree::get().shutdown();
474 osl_removeSignalHandler( pExceptionHandler
);
475 pExceptionHandler
= nullptr;
478 pSVData
->maGDIData
.mxGrfConverter
.reset();
479 pSVData
->mpSettingsConfigItem
.reset();
481 // prevent unnecessary painting during Scheduler shutdown
482 // as this processes all pending events in debug builds.
483 ImplGetSystemDependentDataManager().flushAll();
485 Scheduler::ImplDeInitScheduler();
487 pSVData
->mpWinData
->maMsgBoxImgList
.clear();
488 pSVData
->maCtrlData
.maCheckImgList
.clear();
489 pSVData
->maCtrlData
.maRadioImgList
.clear();
490 pSVData
->maCtrlData
.moDisclosurePlus
.reset();
491 pSVData
->maCtrlData
.moDisclosureMinus
.reset();
492 pSVData
->mpDefaultWin
.disposeAndClear();
495 // See GetSystemClipboard (vcl/source/treelist/transfer2.cxx):
496 if (auto const comp
= css::uno::Reference
<css::lang::XComponent
>(
497 pSVData
->m_xSystemClipboard
, css::uno::UNO_QUERY
))
499 SolarMutexReleaser r
; // unblock pending "clipboard content changed" notifications
500 comp
->dispose(); // will use s_aClipboardSingletonMutex for CWinClipboard
502 pSVData
->m_xSystemClipboard
.clear();
506 DbgGUIDeInitSolarMutexCheck();
509 if ( pSVData
->mpUnoWrapper
)
513 uno::Reference
<frame::XDesktop2
> const xDesktop
= frame::Desktop::create(
514 comphelper::getProcessComponentContext() );
515 xDesktop
->addEventListener(new VCLUnoWrapperDeleter
);
517 catch (uno::Exception
const&)
523 if( pSVData
->mpApp
|| pSVData
->maDeInitHook
.IsSet() )
525 SolarMutexReleaser aReleaser
;
526 // call deinit to deinitialize application class
527 // soffice/sfx implementation disposes the global service manager
528 // Warning: After this call you can't call uno services
531 pSVData
->mpApp
->DeInit();
533 if( pSVData
->maDeInitHook
.IsSet() )
535 pSVData
->maDeInitHook
.Call(nullptr);
539 if ( pSVData
->maAppData
.mxSettings
)
541 if ( pSVData
->maAppData
.mpCfgListener
)
543 pSVData
->maAppData
.mxSettings
->GetSysLocale().GetOptions().RemoveListener( pSVData
->maAppData
.mpCfgListener
);
544 delete pSVData
->maAppData
.mpCfgListener
;
547 pSVData
->maAppData
.mxSettings
.reset();
549 if ( pSVData
->maAppData
.mpAccelMgr
)
551 delete pSVData
->maAppData
.mpAccelMgr
;
552 pSVData
->maAppData
.mpAccelMgr
= nullptr;
554 pSVData
->maAppData
.maKeyListeners
.clear();
555 pSVData
->mpBlendFrameCache
.reset();
557 ImplDeletePrnQueueList();
559 // destroy all Sal interfaces before destroying the instance
560 // and thereby unloading the plugin
561 pSVData
->mpSalSystem
.reset();
562 assert( !pSVData
->maSchedCtx
.mpSalTimer
);
563 delete pSVData
->maSchedCtx
.mpSalTimer
;
564 pSVData
->maSchedCtx
.mpSalTimer
= nullptr;
566 pSVData
->mpDefaultWin
= nullptr;
567 pSVData
->mpIntroWindow
= nullptr;
568 pSVData
->maAppData
.mpActivePopupMenu
= nullptr;
569 pSVData
->maAppData
.mpWheelWindow
= nullptr;
570 pSVData
->maGDIData
.mpFirstWinGraphics
= nullptr;
571 pSVData
->maGDIData
.mpLastWinGraphics
= nullptr;
572 pSVData
->maGDIData
.mpFirstVirGraphics
= nullptr;
573 pSVData
->maGDIData
.mpLastVirGraphics
= nullptr;
574 pSVData
->maGDIData
.mpFirstPrnGraphics
= nullptr;
575 pSVData
->maGDIData
.mpLastPrnGraphics
= nullptr;
576 pSVData
->maGDIData
.mpFirstVirDev
= nullptr;
577 pSVData
->maGDIData
.mpFirstPrinter
= nullptr;
578 pSVData
->maFrameData
.mpFirstFrame
= nullptr;
579 pSVData
->maFrameData
.mpAppWin
= nullptr;
580 pSVData
->maFrameData
.mpActiveApplicationFrame
= nullptr;
581 pSVData
->mpWinData
->mpCaptureWin
= nullptr;
582 pSVData
->mpWinData
->mpLastDeacWin
= nullptr;
583 pSVData
->mpWinData
->mpFirstFloat
= nullptr;
584 pSVData
->mpWinData
->mpExecuteDialogs
.clear();
585 pSVData
->mpWinData
->mpExtTextInputWin
= nullptr;
586 pSVData
->mpWinData
->mpTrackWin
= nullptr;
587 pSVData
->mpWinData
->mpAutoScrollWin
= nullptr;
588 pSVData
->mpWinData
->mpLastWheelWindow
= nullptr;
590 pSVData
->maGDIData
.mxScreenFontList
.reset();
591 pSVData
->maGDIData
.mxScreenFontCache
.reset();
592 pSVData
->dropCaches();
594 comphelper::AccessibleEventNotifier::shutdown();
597 if (pSVData
->mpDefInst
)
599 pSVData
->mpDefInst
->ReleaseYieldMutexAll();
600 DestroySalInstance( pSVData
->mpDefInst
);
601 pSVData
->mpDefInst
= nullptr;
604 // This only works on Linux. On Mac and Windows I get very
605 // weird segment violations.
607 delete pSVData
->mpSalData
;
616 EmbeddedFontsHelper::clearTemporaryFontFiles();
621 // only one call is allowed
622 struct WorkerThreadData
624 oslWorkerFunction pWorker
;
626 WorkerThreadData( oslWorkerFunction pWorker_
, void * pThreadData_
)
627 : pWorker( pWorker_
)
628 , pThreadData( pThreadData_
)
636 static HANDLE hThreadID
= nullptr;
637 static DWORD WINAPI
threadmain( _In_ LPVOID 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 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
= CreateThread(
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: */