Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / app / svmain.cxx
blob72881a6a2933edaf772b4310bf65a5d16df65117
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 "tools/debug.hxx"
28 #include "tools/resmgr.hxx"
30 #include "comphelper/processfactory.hxx"
32 #include "unotools/syslocaleoptions.hxx"
33 #include "vcl/svapp.hxx"
34 #include "vcl/wrkwin.hxx"
35 #include "vcl/cvtgrf.hxx"
36 #include "vcl/scheduler.hxx"
37 #include "vcl/image.hxx"
38 #include "vcl/implimagetree.hxx"
39 #include "vcl/settings.hxx"
40 #include "vcl/unowrap.hxx"
41 #include "vcl/configsettings.hxx"
42 #include "vcl/lazydelete.hxx"
43 #include "vcl/embeddedfontshelper.hxx"
44 #include "vcl/debugevent.hxx"
46 #ifdef WNT
47 #include <svsys.h>
48 #include <process.h>
49 #include <ole2.h>
50 #endif
52 #ifdef ANDROID
53 #include <cppuhelper/bootstrap.hxx>
54 #include <jni.h>
55 #endif
57 #include "salinst.hxx"
58 #include "salwtype.hxx"
59 #include "svdata.hxx"
60 #include "vcl/svmain.hxx"
61 #include "dbggui.hxx"
62 #include "accmgr.hxx"
63 #include "idlemgr.hxx"
64 #include "outdev.h"
65 #include "outfont.hxx"
66 #include "PhysicalFontCollection.hxx"
67 #include "print.h"
68 #include "salgdi.hxx"
69 #include "salsys.hxx"
70 #include "saltimer.hxx"
71 #include "salimestatus.hxx"
72 #include "xconnection.hxx"
74 #include "vcl/opengl/OpenGLContext.hxx"
76 #include "osl/process.h"
77 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
78 #include "com/sun/star/lang/XComponent.hpp"
79 #include "com/sun/star/frame/Desktop.hpp"
81 #include "cppuhelper/implbase1.hxx"
82 #include "uno/current_context.hxx"
84 #include "opengl/zone.hxx"
85 #include "opengl/watchdog.hxx"
87 #if OSL_DEBUG_LEVEL > 0
88 #include <typeinfo>
89 #include "rtl/strbuf.hxx"
90 #endif
92 using namespace ::com::sun::star;
94 oslSignalAction SAL_CALL VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
96 static bool bIn = false;
98 // if we crash again, bail out immediately
99 if ( !bIn )
101 sal_uInt16 nVCLException = 0;
103 // UAE
104 if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
105 (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
106 (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
107 (pInfo->Signal == osl_Signal_DebugBreak) )
109 nVCLException = EXC_SYSTEM;
110 if (OpenGLZone::isInZone())
111 OpenGLZone::hardDisable();
114 // RC
115 if ((pInfo->Signal == osl_Signal_User) &&
116 (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
117 nVCLException = EXC_RSCNOTLOADED;
119 // DISPLAY-Unix
120 if ((pInfo->Signal == osl_Signal_User) &&
121 (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
122 nVCLException = EXC_DISPLAY;
124 // Remote-Client
125 if ((pInfo->Signal == osl_Signal_User) &&
126 (pInfo->UserSignal == OSL_SIGNAL_USER_RVPCONNECTIONERROR) )
127 nVCLException = EXC_REMOTE;
129 if ( nVCLException )
131 bIn = true;
133 SolarMutexGuard aLock;
135 // do not stop timer because otherwise the UAE-Box will not be painted as well
136 ImplSVData* pSVData = ImplGetSVData();
137 if ( pSVData->mpApp )
139 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
140 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
141 pSVData->mpApp->Exception( nVCLException );
142 Application::SetSystemWindowMode( nOldMode );
144 bIn = false;
146 return osl_Signal_ActCallNextHdl;
150 return osl_Signal_ActCallNextHdl;
154 int ImplSVMain()
156 // The 'real' SVMain()
157 ImplSVData* pSVData = ImplGetSVData();
159 DBG_ASSERT( pSVData->mpApp, "no instance of class Application" );
161 int nReturn = EXIT_FAILURE;
163 bool bInit = InitVCL();
165 if( bInit )
167 // call application main
168 pSVData->maAppData.mbInAppMain = true;
169 nReturn = pSVData->mpApp->Main();
170 pSVData->maAppData.mbInAppMain = false;
173 if( pSVData->mxDisplayConnection.is() )
175 pSVData->mxDisplayConnection->terminate();
176 pSVData->mxDisplayConnection.clear();
179 // This is a hack to work around the problem of the asynchronous nature
180 // of bridging accessibility through Java: on shutdown there might still
181 // be some events in the AWT EventQueue, which need the SolarMutex which
182 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
183 // here ..
184 if( pSVData->mxAccessBridge.is() )
187 SolarMutexReleaser aReleaser;
188 pSVData->mxAccessBridge->dispose();
190 pSVData->mxAccessBridge.clear();
193 OpenGLWatchdogThread::stop();
195 DeInitVCL();
197 return nReturn;
200 int SVMain()
202 int nRet;
203 if( !Application::IsConsoleOnly() && ImplSVMainHook( &nRet ) )
204 return nRet;
205 else
206 return ImplSVMain();
209 // This variable is set when no Application object has been instantiated
210 // before InitVCL is called
211 static Application * pOwnSvApp = NULL;
213 // Exception handler. pExceptionHandler != NULL => VCL already inited
214 static oslSignalHandler pExceptionHandler = NULL;
216 class DesktopEnvironmentContext: public cppu::WeakImplHelper1< com::sun::star::uno::XCurrentContext >
218 public:
219 DesktopEnvironmentContext( const com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > & ctx)
220 : m_xNextContext( ctx ) {}
222 // XCurrentContext
223 virtual com::sun::star::uno::Any SAL_CALL getValueByName( const OUString& Name )
224 throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
226 private:
227 com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_xNextContext;
230 uno::Any SAL_CALL DesktopEnvironmentContext::getValueByName( const OUString& Name) throw (uno::RuntimeException, std::exception)
232 uno::Any retVal;
234 if ( Name == "system.desktop-environment" )
236 retVal = uno::makeAny( Application::GetDesktopEnvironment() );
238 else if( m_xNextContext.is() )
240 // Call next context in chain if found
241 retVal = m_xNextContext->getValueByName( Name );
243 return retVal;
246 bool InitVCL()
248 if( pExceptionHandler != NULL )
249 return false;
251 EmbeddedFontsHelper::clearTemporaryFontFiles();
253 if( !ImplGetSVData()->mpApp )
255 pOwnSvApp = new Application();
257 InitSalMain();
259 ImplSVData* pSVData = ImplGetSVData();
261 // remember Main-Thread-Id
262 pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
264 // Initialize Sal
265 pSVData->mpDefInst = CreateSalInstance();
266 if ( !pSVData->mpDefInst )
267 return false;
269 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
270 com::sun::star::uno::setCurrentContext(
271 new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
273 // Initialize application instance (should be done after initialization of VCL SAL part)
274 if( pSVData->mpApp )
275 // call init to initialize application class
276 // soffice/sfx implementation creates the global service manager
277 pSVData->mpApp->Init();
279 pSVData->mpDefInst->AfterAppInit();
281 // Fetch AppFileName and make it absolute before the workdir changes...
282 OUString aExeFileName;
283 osl_getExecutableFile( &aExeFileName.pData );
285 // convert path to native file format
286 OUString aNativeFileName;
287 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
288 pSVData->maAppData.mpAppFileName = new OUString( aNativeFileName );
290 // Initialize global data
291 pSVData->maGDIData.mpScreenFontList = new PhysicalFontCollection;
292 pSVData->maGDIData.mpScreenFontCache = new ImplFontCache;
293 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
295 // Set exception handler
296 pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, NULL);
298 DBGGUI_INIT_SOLARMUTEXCHECK();
300 #if OSL_DEBUG_LEVEL > 0
301 DebugEventInjector::getCreate();
302 #endif
304 return true;
307 namespace
310 /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
311 crash at exit in some special cases when a11y is enabled (e.g., when
312 a bundled extension is registered/deregistered during startup, forcing exit
313 while the app is still in splash screen.)
315 class VCLUnoWrapperDeleter : public cppu::WeakImplHelper1<com::sun::star::lang::XEventListener>
317 virtual void SAL_CALL disposing(lang::EventObject const& rSource) throw(uno::RuntimeException, std::exception) SAL_OVERRIDE;
320 void
321 VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
322 throw(uno::RuntimeException, std::exception)
324 ImplSVData* const pSVData = ImplGetSVData();
325 if (pSVData && pSVData->mpUnoWrapper)
327 pSVData->mpUnoWrapper->Destroy();
328 pSVData->mpUnoWrapper = NULL;
334 void DeInitVCL()
336 ImplSVData* pSVData = ImplGetSVData();
337 pSVData->mbDeInit = true;
339 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
341 // give ime status a chance to destroy its own windows
342 delete pSVData->mpImeStatus;
343 pSVData->mpImeStatus = NULL;
345 #if OSL_DEBUG_LEVEL > 0
346 OStringBuffer aBuf( 256 );
347 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
348 long nTopWindowCount = Application::GetTopWindowCount();
349 long nBadTopWindows = nTopWindowCount;
350 for( long i = 0; i < nTopWindowCount; i++ )
352 vcl::Window* pWin = Application::GetTopWindow( i );
353 // default window will be destroyed further down
354 // but may still be useful during deinit up to that point
355 if( pWin == pSVData->mpDefaultWin )
356 nBadTopWindows--;
357 else
359 aBuf.append( "text = \"" );
360 aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
361 aBuf.append( "\" type = \"" );
362 aBuf.append( typeid(*pWin).name() );
363 aBuf.append( "\", ptr = 0x" );
364 aBuf.append( sal_Int64( pWin ), 16 );
365 aBuf.append( "\n" );
368 DBG_ASSERT( nBadTopWindows==0, aBuf.getStr() );
369 #endif
371 ImplImageTree::get().shutDown();
373 osl_removeSignalHandler( pExceptionHandler);
374 pExceptionHandler = NULL;
376 // free global data
377 delete pSVData->maGDIData.mpGrfConverter;
379 if( pSVData->mpSettingsConfigItem )
380 delete pSVData->mpSettingsConfigItem, pSVData->mpSettingsConfigItem = NULL;
382 if ( pSVData->maAppData.mpIdleMgr )
383 delete pSVData->maAppData.mpIdleMgr;
384 Scheduler::ImplDeInitScheduler();
386 if ( pSVData->maWinData.mpMsgBoxImgList )
388 delete pSVData->maWinData.mpMsgBoxImgList;
389 pSVData->maWinData.mpMsgBoxImgList = NULL;
391 if ( pSVData->maCtrlData.mpCheckImgList )
393 delete pSVData->maCtrlData.mpCheckImgList;
394 pSVData->maCtrlData.mpCheckImgList = NULL;
396 if ( pSVData->maCtrlData.mpRadioImgList )
398 delete pSVData->maCtrlData.mpRadioImgList;
399 pSVData->maCtrlData.mpRadioImgList = NULL;
401 if ( pSVData->maCtrlData.mpPinImgList )
403 delete pSVData->maCtrlData.mpPinImgList;
404 pSVData->maCtrlData.mpPinImgList = NULL;
406 if ( pSVData->maCtrlData.mpSplitHPinImgList )
408 delete pSVData->maCtrlData.mpSplitHPinImgList;
409 pSVData->maCtrlData.mpSplitHPinImgList = NULL;
411 if ( pSVData->maCtrlData.mpSplitVPinImgList )
413 delete pSVData->maCtrlData.mpSplitVPinImgList;
414 pSVData->maCtrlData.mpSplitVPinImgList = NULL;
416 if ( pSVData->maCtrlData.mpSplitHArwImgList )
418 delete pSVData->maCtrlData.mpSplitHArwImgList;
419 pSVData->maCtrlData.mpSplitHArwImgList = NULL;
421 if ( pSVData->maCtrlData.mpSplitVArwImgList )
423 delete pSVData->maCtrlData.mpSplitVArwImgList;
424 pSVData->maCtrlData.mpSplitVArwImgList = NULL;
426 if ( pSVData->maCtrlData.mpDisclosurePlus )
428 delete pSVData->maCtrlData.mpDisclosurePlus;
429 pSVData->maCtrlData.mpDisclosurePlus = NULL;
431 if ( pSVData->maCtrlData.mpDisclosureMinus )
433 delete pSVData->maCtrlData.mpDisclosureMinus;
434 pSVData->maCtrlData.mpDisclosureMinus = NULL;
436 pSVData->mpDefaultWin.disposeAndClear();
438 DBGGUI_DEINIT_SOLARMUTEXCHECK();
440 if ( pSVData->mpUnoWrapper )
444 uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
445 comphelper::getProcessComponentContext() );
446 xDesktop->addEventListener(new VCLUnoWrapperDeleter());
448 catch (uno::Exception const&)
450 // ignore
454 if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
456 SolarMutexReleaser aReleaser;
457 // call deinit to deinitialize application class
458 // soffice/sfx implementation disposes the global service manager
459 // Warning: After this call you can't call uno services
460 if( pSVData->mpApp )
462 pSVData->mpApp->DeInit();
464 if( pSVData->maDeInitHook.IsSet() )
466 pSVData->maDeInitHook.Call(0);
470 if ( pSVData->maAppData.mpSettings )
472 if ( pSVData->maAppData.mpCfgListener )
474 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
475 delete pSVData->maAppData.mpCfgListener;
478 delete pSVData->maAppData.mpSettings;
479 pSVData->maAppData.mpSettings = NULL;
481 if ( pSVData->maAppData.mpAccelMgr )
483 delete pSVData->maAppData.mpAccelMgr;
484 pSVData->maAppData.mpAccelMgr = NULL;
486 if ( pSVData->maAppData.mpAppFileName )
488 delete pSVData->maAppData.mpAppFileName;
489 pSVData->maAppData.mpAppFileName = NULL;
491 if ( pSVData->maAppData.mpAppName )
493 delete pSVData->maAppData.mpAppName;
494 pSVData->maAppData.mpAppName = NULL;
496 if ( pSVData->maAppData.mpDisplayName )
498 delete pSVData->maAppData.mpDisplayName;
499 pSVData->maAppData.mpDisplayName = NULL;
501 if ( pSVData->maAppData.mpEventListeners )
503 delete pSVData->maAppData.mpEventListeners;
504 pSVData->maAppData.mpEventListeners = NULL;
506 if ( pSVData->maAppData.mpKeyListeners )
508 delete pSVData->maAppData.mpKeyListeners;
509 pSVData->maAppData.mpKeyListeners = NULL;
511 if ( pSVData->maAppData.mpPostYieldListeners )
513 delete pSVData->maAppData.mpPostYieldListeners;
514 pSVData->maAppData.mpPostYieldListeners = NULL;
517 if ( pSVData->maAppData.mpFirstHotKey )
518 ImplFreeHotKeyData();
519 if ( pSVData->maAppData.mpFirstEventHook )
520 ImplFreeEventHookData();
522 if (pSVData->mpBlendFrameCache)
523 delete pSVData->mpBlendFrameCache, pSVData->mpBlendFrameCache = NULL;
525 ImplDeletePrnQueueList();
526 delete pSVData->maGDIData.mpScreenFontList;
527 pSVData->maGDIData.mpScreenFontList = NULL;
528 delete pSVData->maGDIData.mpScreenFontCache;
529 pSVData->maGDIData.mpScreenFontCache = NULL;
531 if ( pSVData->mpResMgr )
533 delete pSVData->mpResMgr;
534 pSVData->mpResMgr = NULL;
537 ResMgr::DestroyAllResMgr();
539 // destroy all Sal interfaces before destorying the instance
540 // and thereby unloading the plugin
541 delete pSVData->mpSalSystem;
542 pSVData->mpSalSystem = NULL;
543 delete pSVData->mpSalTimer;
544 pSVData->mpSalTimer = NULL;
546 // Deinit Sal
547 DestroySalInstance( pSVData->mpDefInst );
549 if( pOwnSvApp )
551 delete pOwnSvApp;
552 pOwnSvApp = NULL;
555 EmbeddedFontsHelper::clearTemporaryFontFiles();
558 // only one call is allowed
559 struct WorkerThreadData
561 oslWorkerFunction pWorker;
562 void * pThreadData;
563 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
564 : pWorker( pWorker_ )
565 , pThreadData( pThreadData_ )
570 #ifdef WNT
571 static HANDLE hThreadID = 0;
572 static unsigned __stdcall _threadmain( void *pArgs )
574 OleInitialize( NULL );
575 ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
576 delete (WorkerThreadData*)pArgs;
577 OleUninitialize();
578 hThreadID = 0;
579 return 0;
581 #else
582 static oslThread hThreadID = 0;
583 extern "C"
585 static void SAL_CALL MainWorkerFunction( void* pArgs )
587 static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
588 delete static_cast<WorkerThreadData*>(pArgs);
589 hThreadID = 0;
591 } // extern "C"
592 #endif
594 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
596 #ifdef WNT
597 // sal thread always call CoInitializeEx, so a sysdepen implementation is necessary
599 unsigned uThreadID;
600 hThreadID = (HANDLE)_beginthreadex(
601 NULL, // no security handle
602 0, // stacksize 0 means default
603 _threadmain, // thread worker function
604 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
605 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
606 &uThreadID ); // thread id to fill
607 #else
608 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
609 #endif
612 void JoinMainLoopThread()
614 if( hThreadID )
616 #ifdef WNT
617 WaitForSingleObject(hThreadID, INFINITE);
618 #else
619 osl_joinWithThread(hThreadID);
620 osl_destroyThread( hThreadID );
621 #endif
625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */