nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / app / svmain.cxx
blob4c9fbbe06f48a84908a1116b64d381a64a4f2f9e
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>
21 #include <sal/log.hxx>
23 #include <cassert>
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/QueueInfo.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/vclmain.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/toolkit/unowrap.hxx>
44 #include <configsettings.hxx>
45 #include <vcl/lazydelete.hxx>
46 #include <vcl/embeddedfontshelper.hxx>
47 #include <vcl/toolkit/dialog.hxx>
48 #include <vcl/menu.hxx>
49 #include <vcl/virdev.hxx>
50 #include <vcl/print.hxx>
51 #include <debugevent.hxx>
52 #include <scrwnd.hxx>
54 #ifdef _WIN32
55 #include <svsys.h>
56 #include <process.h>
57 #include <ole2.h>
58 #else
59 #include <stdlib.h>
60 #endif
62 #ifdef ANDROID
63 #include <cppuhelper/bootstrap.hxx>
64 #include <jni.h>
65 #endif
67 #include <impfontcache.hxx>
68 #include <salinst.hxx>
69 #include <svdata.hxx>
70 #include <vcl/svmain.hxx>
71 #include <dbggui.hxx>
72 #include <accmgr.hxx>
73 #include <PhysicalFontCollection.hxx>
74 #include <print.h>
75 #include <salsys.hxx>
76 #include <saltimer.hxx>
77 #include <displayconnectiondispatch.hxx>
79 #include <config_features.h>
80 #include <config_feature_opencl.h>
82 #include <osl/process.h>
83 #include <com/sun/star/lang/XComponent.hpp>
84 #include <com/sun/star/frame/Desktop.hpp>
86 #ifdef _WIN32
87 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
88 #endif
90 #include <comphelper/lok.hxx>
91 #include <cppuhelper/implbase.hxx>
92 #include <uno/current_context.hxx>
94 #include <opencl/OpenCLZone.hxx>
95 #include <opengl/zone.hxx>
96 #include <skia/zone.hxx>
97 #include <watchdog.hxx>
99 #include <basegfx/utils/systemdependentdata.hxx>
100 #include <tools/diagnose_ex.h>
102 #if OSL_DEBUG_LEVEL > 0
103 #include <typeinfo>
104 #include <rtl/strbuf.hxx>
105 #endif
107 using namespace ::com::sun::star;
109 static bool g_bIsLeanException;
111 static oslSignalAction VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
113 static volatile bool bIn = false;
115 // if we crash again, bail out immediately
116 if ( bIn || g_bIsLeanException)
117 return osl_Signal_ActCallNextHdl;
119 ExceptionCategory nVCLException = ExceptionCategory::NONE;
121 // UAE
122 if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
123 (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
124 (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
125 (pInfo->Signal == osl_Signal_DebugBreak) )
127 nVCLException = ExceptionCategory::System;
128 #if HAVE_FEATURE_OPENGL
129 if (OpenGLZone::isInZone())
130 OpenGLZone::hardDisable();
131 #endif
132 #if HAVE_FEATURE_SKIA
133 if (SkiaZone::isInZone())
134 SkiaZone::hardDisable();
135 #endif
136 #if HAVE_FEATURE_OPENCL
137 if (OpenCLZone::isInZone())
139 OpenCLZone::hardDisable();
140 #ifdef _WIN32
141 if (OpenCLInitialZone::isInZone())
142 TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART);
143 #endif
145 #endif
148 // DISPLAY-Unix
149 if ((pInfo->Signal == osl_Signal_User) &&
150 (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
151 nVCLException = ExceptionCategory::UserInterface;
153 if ( nVCLException != ExceptionCategory::NONE )
155 bIn = true;
157 vcl::SolarMutexTryAndBuyGuard aLock;
158 if( aLock.isAcquired())
160 // do not stop timer because otherwise the UAE-Box will not be painted as well
161 ImplSVData* pSVData = ImplGetSVData();
162 if ( pSVData->mpApp )
164 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
165 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
166 pSVData->mpApp->Exception( nVCLException );
167 Application::SetSystemWindowMode( nOldMode );
170 bIn = false;
173 return osl_Signal_ActCallNextHdl;
177 int ImplSVMain()
179 // The 'real' SVMain()
180 ImplSVData* pSVData = ImplGetSVData();
182 SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" );
184 int nReturn = EXIT_FAILURE;
186 const bool bWasInitVCL = IsVCLInit();
187 const bool bInit = bWasInitVCL || InitVCL();
188 int nRet = 0;
189 if (!bWasInitVCL && bInit && pSVData->mpDefInst->SVMainHook(&nRet))
190 return nRet;
192 if( bInit )
194 // call application main
195 pSVData->maAppData.mbInAppMain = true;
196 nReturn = pSVData->mpApp->Main();
197 pSVData->maAppData.mbInAppMain = false;
200 if( pSVData->mxDisplayConnection.is() )
202 pSVData->mxDisplayConnection->terminate();
203 pSVData->mxDisplayConnection.clear();
206 // This is a hack to work around the problem of the asynchronous nature
207 // of bridging accessibility through Java: on shutdown there might still
208 // be some events in the AWT EventQueue, which need the SolarMutex which
209 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
210 // here ..
211 if( pSVData->mxAccessBridge.is() )
214 SolarMutexReleaser aReleaser;
215 pSVData->mxAccessBridge->dispose();
217 pSVData->mxAccessBridge.clear();
220 WatchdogThread::stop();
221 DeInitVCL();
223 return nReturn;
226 int SVMain()
228 return ImplSVMain();
231 // This variable is set when no Application object has been instantiated
232 // before InitVCL is called
233 static Application * pOwnSvApp = nullptr;
235 // Exception handler. pExceptionHandler != NULL => VCL already inited
236 static oslSignalHandler pExceptionHandler = nullptr;
238 namespace {
240 class DesktopEnvironmentContext: public cppu::WeakImplHelper< css::uno::XCurrentContext >
242 public:
243 explicit DesktopEnvironmentContext( const css::uno::Reference< css::uno::XCurrentContext > & ctx)
244 : m_xNextContext( ctx ) {}
246 // XCurrentContext
247 virtual css::uno::Any SAL_CALL getValueByName( const OUString& Name ) override;
249 private:
250 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 bool IsVCLInit()
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 (IsVCLInit())
294 SAL_INFO("vcl.app", "Double initialization of vcl");
295 return true;
298 if( pExceptionHandler != nullptr )
299 return false;
301 EmbeddedFontsHelper::clearTemporaryFontFiles();
303 if( !ImplGetSVData()->mpApp )
305 pOwnSvApp = new Application();
308 ImplSVData* pSVData = ImplGetSVData();
310 // remember Main-Thread-Id
311 pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
313 // Initialize Sal
314 pSVData->mpDefInst = CreateSalInstance();
315 if ( !pSVData->mpDefInst )
316 return false;
318 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
319 css::uno::setCurrentContext(
320 new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
322 // Initialize application instance (should be done after initialization of VCL SAL part)
323 if (pSVData->mpApp)
325 // call init to initialize application class
326 // soffice/sfx implementation creates the global service manager
327 pSVData->mpApp->Init();
332 //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can
333 //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL
334 //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python)
335 //to match their translations to our preferred UI language
336 OUString aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(".UTF-8"));
337 if (!aLocaleString.isEmpty())
339 MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was
340 OUString envVar("LANGUAGE");
341 osl_setEnvironment(envVar.pData, aLocaleString.pData);
344 catch (const uno::Exception &)
346 TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:");
349 pSVData->mpDefInst->AfterAppInit();
351 // Fetch AppFileName and make it absolute before the workdir changes...
352 OUString aExeFileName;
353 osl_getExecutableFile( &aExeFileName.pData );
355 // convert path to native file format
356 OUString aNativeFileName;
357 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
358 pSVData->maAppData.mxAppFileName = aNativeFileName;
360 // Initialize global data
361 pSVData->maGDIData.mxScreenFontList = std::make_shared<PhysicalFontCollection>();
362 pSVData->maGDIData.mxScreenFontCache = std::make_shared<ImplFontCache>();
363 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
365 g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr;
366 // Set exception handler
367 pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr);
369 #ifndef NDEBUG
370 DbgGUIInitSolarMutexCheck();
371 #endif
373 #if OSL_DEBUG_LEVEL > 0
374 DebugEventInjector::getCreate();
375 #endif
377 #ifndef _WIN32
378 // Clear startup notification details for child processes
379 // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
380 unsetenv("DESKTOP_STARTUP_ID");
381 #endif
383 return true;
386 namespace
389 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
390 crash at exit in some special cases when a11y is enabled (e.g., when
391 a bundled extension is registered/deregistered during startup, forcing exit
392 while the app is still in splash screen.)
394 class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener>
396 virtual void SAL_CALL disposing(lang::EventObject const& rSource) override;
399 void
400 VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
402 ImplSVData* const pSVData = ImplGetSVData();
403 if (pSVData && pSVData->mpUnoWrapper)
405 pSVData->mpUnoWrapper->Destroy();
406 pSVData->mpUnoWrapper = nullptr;
412 void DeInitVCL()
414 // The LOK Windows map container should be empty
415 assert(vcl::Window::IsLOKWindowsEmpty());
417 //rhbz#1444437, when using LibreOffice like a library you can't realistically
418 //tear everything down and recreate them on the next call, there's too many
419 //(c++) singletons that point to stuff that gets deleted during shutdown
420 //which won't be recreated on restart.
421 if (comphelper::LibreOfficeKit::isActive())
422 return;
425 SolarMutexReleaser r; // unblock threads blocked on that so we can join
426 ::comphelper::JoinAsyncEventNotifiers();
428 ImplSVData* pSVData = ImplGetSVData();
430 // lp#1560328: clear cache before disposing rest of VCL
431 if(pSVData->mpBlendFrameCache)
432 pSVData->mpBlendFrameCache->m_aLastResult.Clear();
433 pSVData->mbDeInit = true;
435 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
437 #if OSL_DEBUG_LEVEL > 0
438 OStringBuffer aBuf( 256 );
439 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
440 tools::Long nTopWindowCount = Application::GetTopWindowCount();
441 tools::Long nBadTopWindows = nTopWindowCount;
442 for( tools::Long i = 0; i < nTopWindowCount; i++ )
444 vcl::Window* pWin = Application::GetTopWindow( i );
445 // default window will be destroyed further down
446 // but may still be useful during deinit up to that point
447 if( pWin == pSVData->mpDefaultWin )
448 nBadTopWindows--;
449 else
451 aBuf.append( "text = \"" );
452 aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
453 aBuf.append( "\" type = \"" );
454 aBuf.append( typeid(*pWin).name() );
455 aBuf.append( "\", ptr = 0x" );
456 aBuf.append( reinterpret_cast<sal_Int64>( pWin ), 16 );
457 aBuf.append( "\n" );
460 SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
461 #endif
463 ImageTree::get().shutdown();
465 osl_removeSignalHandler( pExceptionHandler);
466 pExceptionHandler = nullptr;
468 // free global data
469 if (pSVData->maGDIData.mpGrfConverter)
471 delete pSVData->maGDIData.mpGrfConverter;
472 pSVData->maGDIData.mpGrfConverter = nullptr;
475 pSVData->mpSettingsConfigItem.reset();
477 // prevent unnecessary painting during Scheduler shutdown
478 // as this processes all pending events in debug builds.
479 ImplGetSystemDependentDataManager().flushAll();
481 Scheduler::ImplDeInitScheduler();
483 pSVData->mpWinData->maMsgBoxImgList.clear();
484 pSVData->maCtrlData.maCheckImgList.clear();
485 pSVData->maCtrlData.maRadioImgList.clear();
486 pSVData->maCtrlData.mpDisclosurePlus.reset();
487 pSVData->maCtrlData.mpDisclosureMinus.reset();
488 pSVData->mpDefaultWin.disposeAndClear();
490 #if defined _WIN32
491 // See GetSystemClipboard (vcl/source/treelist/transfer2.cxx):
492 if (auto const comp = css::uno::Reference<css::lang::XComponent>(
493 pSVData->m_xSystemClipboard, css::uno::UNO_QUERY))
495 SolarMutexReleaser r; // unblock pending "clipboard content changed" notifications
496 comp->dispose(); // will use CWinClipbImpl::s_aMutex
498 pSVData->m_xSystemClipboard.clear();
499 #endif
501 #ifndef NDEBUG
502 DbgGUIDeInitSolarMutexCheck();
503 #endif
505 if ( pSVData->mpUnoWrapper )
509 uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
510 comphelper::getProcessComponentContext() );
511 xDesktop->addEventListener(new VCLUnoWrapperDeleter);
513 catch (uno::Exception const&)
515 // ignore
519 if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
521 SolarMutexReleaser aReleaser;
522 // call deinit to deinitialize application class
523 // soffice/sfx implementation disposes the global service manager
524 // Warning: After this call you can't call uno services
525 if( pSVData->mpApp )
527 pSVData->mpApp->DeInit();
529 if( pSVData->maDeInitHook.IsSet() )
531 pSVData->maDeInitHook.Call(nullptr);
535 if ( pSVData->maAppData.mpSettings )
537 if ( pSVData->maAppData.mpCfgListener )
539 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
540 delete pSVData->maAppData.mpCfgListener;
543 pSVData->maAppData.mpSettings.reset();
545 if ( pSVData->maAppData.mpAccelMgr )
547 delete pSVData->maAppData.mpAccelMgr;
548 pSVData->maAppData.mpAccelMgr = nullptr;
550 pSVData->maAppData.maKeyListeners.clear();
551 pSVData->mpBlendFrameCache.reset();
553 ImplDeletePrnQueueList();
555 // destroy all Sal interfaces before destroying the instance
556 // and thereby unloading the plugin
557 pSVData->mpSalSystem.reset();
558 assert( !pSVData->maSchedCtx.mpSalTimer );
559 delete pSVData->maSchedCtx.mpSalTimer;
560 pSVData->maSchedCtx.mpSalTimer = nullptr;
562 pSVData->mpDefaultWin = nullptr;
563 pSVData->mpIntroWindow = nullptr;
564 pSVData->maAppData.mpActivePopupMenu = nullptr;
565 pSVData->maAppData.mpWheelWindow = nullptr;
566 pSVData->maGDIData.mpFirstWinGraphics = nullptr;
567 pSVData->maGDIData.mpLastWinGraphics = nullptr;
568 pSVData->maGDIData.mpFirstVirGraphics = nullptr;
569 pSVData->maGDIData.mpLastVirGraphics = nullptr;
570 pSVData->maGDIData.mpFirstPrnGraphics = nullptr;
571 pSVData->maGDIData.mpLastPrnGraphics = nullptr;
572 pSVData->maGDIData.mpFirstVirDev = nullptr;
573 pSVData->maGDIData.mpFirstPrinter = nullptr;
574 pSVData->maFrameData.mpFirstFrame = nullptr;
575 pSVData->maFrameData.mpAppWin = nullptr;
576 pSVData->maFrameData.mpActiveApplicationFrame = nullptr;
577 pSVData->mpWinData->mpCaptureWin = nullptr;
578 pSVData->mpWinData->mpLastDeacWin = nullptr;
579 pSVData->mpWinData->mpFirstFloat = nullptr;
580 pSVData->mpWinData->mpExecuteDialogs.clear();
581 pSVData->mpWinData->mpExtTextInputWin = nullptr;
582 pSVData->mpWinData->mpTrackWin = nullptr;
583 pSVData->mpWinData->mpAutoScrollWin = nullptr;
584 pSVData->mpWinData->mpLastWheelWindow = nullptr;
586 pSVData->maGDIData.mxScreenFontList.reset();
587 pSVData->maGDIData.mxScreenFontCache.reset();
588 pSVData->maGDIData.maScaleCache.remove_if([](const lru_scale_cache::key_value_pair_t&)
589 { return true; });
591 pSVData->maGDIData.maThemeDrawCommandsCache.clear();
592 pSVData->maGDIData.maThemeImageCache.clear();
594 // Deinit Sal
595 if (pSVData->mpDefInst)
597 DestroySalInstance( pSVData->mpDefInst );
598 pSVData->mpDefInst = nullptr;
601 if( pOwnSvApp )
603 delete pOwnSvApp;
604 pOwnSvApp = nullptr;
607 EmbeddedFontsHelper::clearTemporaryFontFiles();
610 namespace {
612 // only one call is allowed
613 struct WorkerThreadData
615 oslWorkerFunction pWorker;
616 void * pThreadData;
617 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
618 : pWorker( pWorker_ )
619 , pThreadData( pThreadData_ )
626 #ifdef _WIN32
627 static HANDLE hThreadID = nullptr;
628 static unsigned __stdcall threadmain( void *pArgs )
630 OleInitialize( nullptr );
631 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
632 delete static_cast<WorkerThreadData*>(pArgs);
633 OleUninitialize();
634 hThreadID = nullptr;
635 return 0;
637 #else
638 static oslThread hThreadID = nullptr;
639 extern "C"
641 static void MainWorkerFunction( void* pArgs )
643 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
644 delete static_cast<WorkerThreadData*>(pArgs);
645 hThreadID = nullptr;
647 } // extern "C"
648 #endif
650 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
652 #ifdef _WIN32
653 // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
655 unsigned uThreadID;
656 hThreadID = reinterpret_cast<HANDLE>(_beginthreadex(
657 nullptr, // no security handle
658 0, // stacksize 0 means default
659 threadmain, // thread worker function
660 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
661 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
662 &uThreadID )); // thread id to fill
663 #else
664 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
665 #endif
668 void JoinMainLoopThread()
670 if( hThreadID )
672 #ifdef _WIN32
673 WaitForSingleObject(hThreadID, INFINITE);
674 #else
675 osl_joinWithThread(hThreadID);
676 osl_destroyThread( hThreadID );
677 #endif
681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */