/src/libreoffice/vcl/source/app/svmain.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | #include <sal/log.hxx> |
22 | | |
23 | | #include <cassert> |
24 | | |
25 | | #include <osl/file.hxx> |
26 | | #include <osl/signal.h> |
27 | | |
28 | | #include <desktop/exithelper.h> |
29 | | |
30 | | #include <comphelper/accessibleeventnotifier.hxx> |
31 | | #include <comphelper/processfactory.hxx> |
32 | | #include <comphelper/asyncnotification.hxx> |
33 | | #include <drawinglayer/primitive2d/BufferedDecompositionFlusher.hxx> |
34 | | #include <i18nlangtag/mslangid.hxx> |
35 | | #include <unotools/syslocale.hxx> |
36 | | #include <unotools/syslocaleoptions.hxx> |
37 | | #include <utility> |
38 | | #include <vcl/exceptiontypes.hxx> |
39 | | #include <vcl/QueueInfo.hxx> |
40 | | #include <vcl/svapp.hxx> |
41 | | #include <vcl/vclmain.hxx> |
42 | | #include <vcl/wrkwin.hxx> |
43 | | #include <vcl/cvtgrf.hxx> |
44 | | #include <vcl/scheduler.hxx> |
45 | | #include <vcl/image.hxx> |
46 | | #include <vcl/ImageTree.hxx> |
47 | | #include <vcl/settings.hxx> |
48 | | #include <vcl/toolkit/unowrap.hxx> |
49 | | #include <tools/lazydelete.hxx> |
50 | | #include <vcl/embeddedfontsmanager.hxx> |
51 | | #include <vcl/toolkit/dialog.hxx> |
52 | | #include <vcl/menu.hxx> |
53 | | #include <vcl/virdev.hxx> |
54 | | #include <vcl/print.hxx> |
55 | | |
56 | | #include <bitmap/BlendFrameCache.hxx> |
57 | | #include <debugevent.hxx> |
58 | | #include <scrwnd.hxx> |
59 | | #include <windowdev.hxx> |
60 | | #include <svdata.hxx> |
61 | | |
62 | | #ifdef _WIN32 |
63 | | #include <win/svsys.h> |
64 | | #include <process.h> |
65 | | #include <ole2.h> |
66 | | #else |
67 | | #include <stdlib.h> |
68 | | #endif |
69 | | |
70 | | #ifdef ANDROID |
71 | | #include <cppuhelper/bootstrap.hxx> |
72 | | #include <jni.h> |
73 | | #endif |
74 | | |
75 | | #include <impfontcache.hxx> |
76 | | #include <salinst.hxx> |
77 | | #include <vcl/svmain.hxx> |
78 | | #include <dbggui.hxx> |
79 | | #include <accmgr.hxx> |
80 | | #include <font/PhysicalFontCollection.hxx> |
81 | | #include <print.h> |
82 | | #include <salsys.hxx> |
83 | | #include <saltimer.hxx> |
84 | | #include <displayconnectiondispatch.hxx> |
85 | | |
86 | | #include <config_features.h> |
87 | | #include <config_feature_opencl.h> |
88 | | #include <systools/opensslinit.hxx> |
89 | | |
90 | | #include <osl/process.h> |
91 | | #include <com/sun/star/lang/XComponent.hpp> |
92 | | #include <com/sun/star/frame/Desktop.hpp> |
93 | | |
94 | | #ifdef _WIN32 |
95 | | #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> |
96 | | #endif |
97 | | |
98 | | #include <comphelper/lok.hxx> |
99 | | #include <cppuhelper/implbase.hxx> |
100 | | #include <uno/current_context.hxx> |
101 | | |
102 | | #include <opencl/OpenCLZone.hxx> |
103 | | #include <opengl/zone.hxx> |
104 | | #include <skia/zone.hxx> |
105 | | #include <watchdog.hxx> |
106 | | |
107 | | #include <basegfx/utils/systemdependentdata.hxx> |
108 | | #include <comphelper/diagnose_ex.hxx> |
109 | | |
110 | | #if OSL_DEBUG_LEVEL > 0 |
111 | | #include <typeinfo> |
112 | | #include <rtl/strbuf.hxx> |
113 | | #endif |
114 | | |
115 | | #ifdef LINUX |
116 | | #include <unx/gendata.hxx> |
117 | | #endif |
118 | | |
119 | | using namespace ::com::sun::star; |
120 | | |
121 | | static bool g_bIsLeanException; |
122 | | |
123 | | static oslSignalAction VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo) |
124 | 0 | { |
125 | 0 | static volatile bool bIn = false; |
126 | | |
127 | | // if we crash again, bail out immediately |
128 | 0 | if ( bIn || g_bIsLeanException) |
129 | 0 | return osl_Signal_ActCallNextHdl; |
130 | | |
131 | 0 | ExceptionCategory nVCLException = ExceptionCategory::NONE; |
132 | | |
133 | | // UAE |
134 | 0 | if ( (pInfo->Signal == osl_Signal_AccessViolation) || |
135 | 0 | (pInfo->Signal == osl_Signal_IntegerDivideByZero) || |
136 | 0 | (pInfo->Signal == osl_Signal_FloatDivideByZero) || |
137 | 0 | (pInfo->Signal == osl_Signal_DebugBreak) ) |
138 | 0 | { |
139 | 0 | nVCLException = ExceptionCategory::System; |
140 | | #if HAVE_FEATURE_OPENGL |
141 | | if (OpenGLZone::isInZone()) |
142 | | OpenGLZone::hardDisable(); |
143 | | #endif |
144 | | #if HAVE_FEATURE_SKIA |
145 | | if (SkiaZone::isInZone()) |
146 | | SkiaZone::hardDisable(); |
147 | | #endif |
148 | | #if HAVE_FEATURE_OPENCL |
149 | | if (OpenCLZone::isInZone()) |
150 | | { |
151 | | OpenCLZone::hardDisable(); |
152 | | #ifdef _WIN32 |
153 | | if (OpenCLInitialZone::isInZone()) |
154 | | TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART); |
155 | | #endif |
156 | | } |
157 | | #endif |
158 | 0 | } |
159 | | |
160 | | // DISPLAY-Unix |
161 | 0 | if ((pInfo->Signal == osl_Signal_User) && |
162 | 0 | (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) ) |
163 | 0 | nVCLException = ExceptionCategory::UserInterface; |
164 | |
|
165 | 0 | if ( nVCLException != ExceptionCategory::NONE ) |
166 | 0 | { |
167 | 0 | bIn = true; |
168 | |
|
169 | 0 | vcl::SolarMutexTryAndBuyGuard aLock; |
170 | 0 | if( aLock.isAcquired()) |
171 | 0 | { |
172 | | // do not stop timer because otherwise the UAE-Box will not be painted as well |
173 | 0 | ImplSVData* pSVData = ImplGetSVData(); |
174 | 0 | if ( pSVData->mpApp ) |
175 | 0 | { |
176 | 0 | SystemWindowFlags nOldMode = Application::GetSystemWindowMode(); |
177 | 0 | Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE ); |
178 | 0 | pSVData->mpApp->Exception( nVCLException ); |
179 | 0 | Application::SetSystemWindowMode( nOldMode ); |
180 | 0 | } |
181 | 0 | } |
182 | 0 | bIn = false; |
183 | 0 | } |
184 | |
|
185 | 0 | return osl_Signal_ActCallNextHdl; |
186 | |
|
187 | 0 | } |
188 | | |
189 | | int ImplSVMain() |
190 | 0 | { |
191 | | // The 'real' SVMain() |
192 | 0 | ImplSVData* pSVData = ImplGetSVData(); |
193 | |
|
194 | 0 | SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" ); |
195 | | |
196 | 0 | if ( IsVCLInit() ) |
197 | 0 | return EXIT_SUCCESS; |
198 | | |
199 | 0 | #if !defined(_WIN32) && !defined(SYSTEM_OPENSSL) |
200 | 0 | static constexpr OUString name(u"SSL_CERT_FILE"_ustr); |
201 | 0 | OUString temp; |
202 | 0 | if (osl_getEnvironment(name.pData, &temp.pData) == osl_Process_E_NotFound) |
203 | 0 | { |
204 | | // Try to point bundled OpenSSL to some system certificate file |
205 | | // ... this only works if the client actually calls |
206 | | // SSL_CTX_set_default_verify_paths() or similar; e.g. python ssl. |
207 | 0 | char const*const path = GetCABundleFile(); |
208 | 0 | if (path == nullptr) { |
209 | 0 | SAL_WARN("vcl", "no OpenSSL CA certificate bundle found"); |
210 | 0 | } else { |
211 | 0 | OUString const filepath(::rtl::OStringToOUString( |
212 | 0 | ::std::string_view(path), osl_getThreadTextEncoding())); |
213 | 0 | osl_setEnvironment(name.pData, filepath.pData); |
214 | 0 | } |
215 | 0 | } |
216 | 0 | #endif |
217 | | |
218 | 0 | if ( !InitVCL() ) |
219 | 0 | return EXIT_FAILURE; |
220 | | |
221 | 0 | return GetSalInstance()->SVMainRun(); |
222 | 0 | } |
223 | | |
224 | | int ImplSVMainRun() |
225 | 0 | { |
226 | 0 | ImplSVData* pSVData = ImplGetSVData(); |
227 | |
|
228 | 0 | int nReturn = EXIT_FAILURE; |
229 | |
|
230 | 0 | if( IsVCLInit() ) |
231 | 0 | { |
232 | | // call application main |
233 | 0 | pSVData->maAppData.mbInAppMain = true; |
234 | 0 | nReturn = pSVData->mpApp->Main(); |
235 | 0 | pSVData->maAppData.mbInAppMain = false; |
236 | 0 | } |
237 | |
|
238 | 0 | if( pSVData->mxDisplayConnection.is() ) |
239 | 0 | { |
240 | 0 | pSVData->mxDisplayConnection->terminate(); |
241 | 0 | pSVData->mxDisplayConnection.clear(); |
242 | 0 | } |
243 | |
|
244 | 0 | WatchdogThread::stop(); |
245 | 0 | DeInitVCL(); |
246 | |
|
247 | 0 | return nReturn; |
248 | 0 | } |
249 | | |
250 | | int SVMain() |
251 | 0 | { |
252 | 0 | return ImplSVMain(); |
253 | 0 | } |
254 | | |
255 | | // This variable is set when no Application object has been instantiated |
256 | | // before InitVCL is called |
257 | | static Application * pOwnSvApp = nullptr; |
258 | | |
259 | | // Exception handler. pExceptionHandler != NULL => VCL already inited |
260 | | static oslSignalHandler pExceptionHandler = nullptr; |
261 | | |
262 | | bool IsVCLInit() |
263 | 110 | { |
264 | 110 | ImplSVData* pSVData = ImplGetSVData(); |
265 | 110 | return pExceptionHandler != nullptr && |
266 | 6 | pSVData->mpApp != nullptr && |
267 | 6 | pSVData->mpDefInst != nullptr; |
268 | 110 | } |
269 | | |
270 | | #ifdef DBG_UTIL |
271 | | namespace vclmain |
272 | | { |
273 | | bool isAlive() |
274 | | { |
275 | | return ImplGetSVData()->mpDefInst; |
276 | | } |
277 | | } |
278 | | #endif |
279 | | |
280 | | |
281 | | bool InitVCL() |
282 | 104 | { |
283 | 104 | if (IsVCLInit()) |
284 | 0 | { |
285 | 0 | SAL_INFO("vcl.app", "Double initialization of vcl"); |
286 | 0 | return true; |
287 | 0 | } |
288 | | |
289 | 104 | if( pExceptionHandler != nullptr ) |
290 | 0 | return false; |
291 | | |
292 | 104 | EmbeddedFontsManager::clearTemporaryFontFiles(); |
293 | | |
294 | 104 | if( !ImplGetSVData()->mpApp ) |
295 | 104 | { |
296 | 104 | pOwnSvApp = new Application(); |
297 | 104 | } |
298 | | |
299 | 104 | ImplSVData* pSVData = ImplGetSVData(); |
300 | | |
301 | | // remember Main-Thread-Id |
302 | 104 | pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier(); |
303 | | |
304 | | // Initialize Sal |
305 | 104 | pSVData->mpDefInst = CreateSalInstance(); |
306 | 104 | if ( !pSVData->mpDefInst ) |
307 | 0 | return false; |
308 | 104 | pSVData->mpDefInst->AcquireYieldMutex(); |
309 | | |
310 | | // Initialize application instance (should be done after initialization of VCL SAL part) |
311 | 104 | if (pSVData->mpApp) |
312 | 104 | { |
313 | | // call init to initialize application class |
314 | | // soffice/sfx implementation creates the global service manager |
315 | 104 | pSVData->mpApp->Init(); |
316 | 104 | } |
317 | | |
318 | 104 | try |
319 | 104 | { |
320 | | //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can |
321 | | //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL |
322 | | //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python) |
323 | | //to match their translations to our preferred UI language |
324 | 104 | OUString aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(u".UTF-8")); |
325 | 104 | if (!aLocaleString.isEmpty()) |
326 | 104 | { |
327 | 104 | MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was |
328 | 104 | OUString envVar(u"LANGUAGE"_ustr); |
329 | 104 | osl_setEnvironment(envVar.pData, aLocaleString.pData); |
330 | 104 | } |
331 | 104 | } |
332 | 104 | catch (const uno::Exception &) |
333 | 104 | { |
334 | 0 | TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:"); |
335 | 0 | } |
336 | | |
337 | 104 | pSVData->mpDefInst->AfterAppInit(); |
338 | | |
339 | | // Fetch AppFileName and make it absolute before the workdir changes... |
340 | 104 | OUString aExeFileName; |
341 | 104 | osl_getExecutableFile( &aExeFileName.pData ); |
342 | | |
343 | | // convert path to native file format |
344 | 104 | OUString aNativeFileName; |
345 | 104 | osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName ); |
346 | 104 | pSVData->maAppData.mxAppFileName = aNativeFileName; |
347 | | |
348 | | // Initialize global data |
349 | 104 | pSVData->maGDIData.mxScreenFontList = std::make_shared<vcl::font::PhysicalFontCollection>(); |
350 | 104 | pSVData->maGDIData.mxScreenFontCache = std::make_shared<ImplFontCache>(); |
351 | 104 | pSVData->maGDIData.mxGrfConverter.reset(new GraphicConverter); |
352 | | |
353 | 104 | g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr; |
354 | | // Set exception handler |
355 | 104 | pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr); |
356 | | |
357 | | #ifndef NDEBUG |
358 | | DbgGUIInitSolarMutexCheck(); |
359 | | #endif |
360 | | |
361 | | #if OSL_DEBUG_LEVEL > 0 |
362 | | DebugEventInjector::getCreate(); |
363 | | #endif |
364 | | |
365 | 104 | #ifndef _WIN32 |
366 | | // Clear startup notification details for child processes |
367 | | // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion |
368 | 104 | unsetenv("DESKTOP_STARTUP_ID"); |
369 | 104 | #endif |
370 | | |
371 | 104 | return true; |
372 | 104 | } |
373 | | |
374 | | namespace |
375 | | { |
376 | | |
377 | | /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids |
378 | | crash at exit in some special cases when a11y is enabled (e.g., when |
379 | | a bundled extension is registered/deregistered during startup, forcing exit |
380 | | while the app is still in splash screen.) |
381 | | */ |
382 | | class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener> |
383 | | { |
384 | | virtual void SAL_CALL disposing(lang::EventObject const& rSource) override; |
385 | | }; |
386 | | |
387 | | void |
388 | | VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */) |
389 | 0 | { |
390 | 0 | ImplSVData* const pSVData = ImplGetSVData(); |
391 | 0 | if (pSVData && pSVData->mpUnoWrapper) |
392 | 0 | { |
393 | 0 | pSVData->mpUnoWrapper->Destroy(); |
394 | 0 | pSVData->mpUnoWrapper = nullptr; |
395 | 0 | } |
396 | 0 | } |
397 | | |
398 | | } |
399 | | |
400 | | void DeInitVCL() |
401 | 0 | { |
402 | | // The LOK Windows map container should be empty |
403 | 0 | assert(vcl::Window::IsLOKWindowsEmpty()); |
404 | | |
405 | | //rhbz#1444437, when using LibreOffice like a library you can't realistically |
406 | | //tear everything down and recreate them on the next call, there's too many |
407 | | //(c++) singletons that point to stuff that gets deleted during shutdown |
408 | | //which won't be recreated on restart. |
409 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
410 | 0 | return; |
411 | | |
412 | 0 | { |
413 | 0 | SolarMutexReleaser r; // unblock threads blocked on that so we can join |
414 | 0 | ::comphelper::JoinAsyncEventNotifiers(); |
415 | 0 | } |
416 | 0 | ImplSVData* pSVData = ImplGetSVData(); |
417 | | |
418 | | // This is a hack to work around the problem of the asynchronous nature |
419 | | // of bridging accessibility through Java: on shutdown there might still |
420 | | // be some events in the AWT EventQueue, which need the SolarMutex which |
421 | | // - on the other hand - is destroyed in DeInitVCL(). So empty the queue |
422 | | // here .. |
423 | 0 | if (pSVData->mxAccessBridge.is()) |
424 | 0 | { |
425 | 0 | { |
426 | 0 | SolarMutexReleaser aReleaser; |
427 | 0 | pSVData->mxAccessBridge->dispose(); |
428 | 0 | } |
429 | 0 | pSVData->mxAccessBridge.clear(); |
430 | 0 | } |
431 | | |
432 | | // lp#1560328: clear cache before disposing rest of VCL |
433 | 0 | if(pSVData->mpBlendFrameCache) |
434 | 0 | pSVData->mpBlendFrameCache->m_aLastResult = Bitmap(); |
435 | 0 | pSVData->mbDeInit = true; |
436 | | |
437 | | // Some events may need to access objects destroyed in ImplDeleteOnDeInit, so process them first |
438 | 0 | Scheduler::ProcessEventsToIdle(); |
439 | |
|
440 | 0 | { |
441 | | // unblock we will wait for things that want to take the SolarMutex on another thread |
442 | 0 | SolarMutexReleaser aReleaser; |
443 | 0 | drawinglayer::primitive2d::BufferedDecompositionFlusher::shutdown(); |
444 | 0 | } |
445 | |
|
446 | 0 | tools::DeleteOnDeinitBase::ImplDeleteOnDeInit(); |
447 | |
|
448 | | #if OSL_DEBUG_LEVEL > 0 |
449 | | OStringBuffer aBuf( 256 ); |
450 | | aBuf.append( "DeInitVCL: some top Windows are still alive\n" ); |
451 | | tools::Long nTopWindowCount = Application::GetTopWindowCount(); |
452 | | tools::Long nBadTopWindows = nTopWindowCount; |
453 | | for( tools::Long i = 0; i < nTopWindowCount; i++ ) |
454 | | { |
455 | | vcl::Window* pWin = Application::GetTopWindow( i ); |
456 | | // default window will be destroyed further down |
457 | | // but may still be useful during deinit up to that point |
458 | | if( pWin == pSVData->mpDefaultWin ) |
459 | | nBadTopWindows--; |
460 | | else |
461 | | { |
462 | | aBuf.append( "text = \"" |
463 | | + OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) |
464 | | + "\" type = \"" |
465 | | + typeid(*pWin).name() |
466 | | + "\", ptr = 0x" |
467 | | + OString::number(reinterpret_cast<sal_Int64>( pWin ), 16 ) |
468 | | + "\n" ); |
469 | | } |
470 | | } |
471 | | SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() ); |
472 | | #endif |
473 | |
|
474 | 0 | ImageTree::get().shutdown(); |
475 | |
|
476 | 0 | osl_removeSignalHandler( pExceptionHandler); |
477 | 0 | pExceptionHandler = nullptr; |
478 | | |
479 | | // free global data |
480 | 0 | pSVData->maGDIData.mxGrfConverter.reset(); |
481 | | |
482 | | // prevent unnecessary painting during Scheduler shutdown |
483 | | // as this processes all pending events in debug builds. |
484 | 0 | ImplGetSystemDependentDataManager().flushAll(); |
485 | |
|
486 | | #if defined _WIN32 |
487 | | // See GetSystemClipboard (vcl/source/treelist/transfer2.cxx): |
488 | | if (auto const comp = css::uno::Reference<css::lang::XComponent>( |
489 | | pSVData->m_xSystemClipboard, css::uno::UNO_QUERY)) |
490 | | { |
491 | | SolarMutexReleaser r; // unblock pending "clipboard content changed" notifications |
492 | | comp->dispose(); // will use s_aClipboardSingletonMutex for CWinClipboard |
493 | | } |
494 | | pSVData->m_xSystemClipboard.clear(); |
495 | | #endif |
496 | |
|
497 | 0 | Scheduler::ImplDeInitScheduler(); |
498 | |
|
499 | 0 | pSVData->mpWinData->maMsgBoxImgList.clear(); |
500 | 0 | pSVData->maCtrlData.maCheckImgList.clear(); |
501 | 0 | pSVData->maCtrlData.maRadioImgList.clear(); |
502 | 0 | pSVData->maCtrlData.moDisclosurePlus.reset(); |
503 | 0 | pSVData->maCtrlData.moDisclosureMinus.reset(); |
504 | 0 | pSVData->mpDefaultWin.disposeAndClear(); |
505 | |
|
506 | | #ifndef NDEBUG |
507 | | DbgGUIDeInitSolarMutexCheck(); |
508 | | #endif |
509 | |
|
510 | 0 | if ( pSVData->mpUnoWrapper ) |
511 | 0 | { |
512 | 0 | try |
513 | 0 | { |
514 | 0 | uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create( |
515 | 0 | comphelper::getProcessComponentContext() ); |
516 | 0 | xDesktop->addEventListener(new VCLUnoWrapperDeleter); |
517 | 0 | } |
518 | 0 | catch (uno::Exception const&) |
519 | 0 | { |
520 | | // ignore |
521 | 0 | } |
522 | 0 | } |
523 | |
|
524 | 0 | if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() ) |
525 | 0 | { |
526 | 0 | SolarMutexReleaser aReleaser; |
527 | | // call deinit to deinitialize application class |
528 | | // soffice/sfx implementation disposes the global service manager |
529 | | // Warning: After this call you can't call uno services |
530 | 0 | if( pSVData->mpApp ) |
531 | 0 | { |
532 | 0 | pSVData->mpApp->DeInit(); |
533 | 0 | } |
534 | 0 | if( pSVData->maDeInitHook.IsSet() ) |
535 | 0 | { |
536 | 0 | pSVData->maDeInitHook.Call(nullptr); |
537 | 0 | } |
538 | 0 | } |
539 | |
|
540 | 0 | if ( pSVData->maAppData.mxSettings ) |
541 | 0 | { |
542 | 0 | if ( pSVData->maAppData.mpCfgListener ) |
543 | 0 | { |
544 | 0 | pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener ); |
545 | 0 | delete pSVData->maAppData.mpCfgListener; |
546 | 0 | } |
547 | |
|
548 | 0 | pSVData->maAppData.mxSettings.reset(); |
549 | 0 | } |
550 | 0 | if ( pSVData->maAppData.mpAccelMgr ) |
551 | 0 | { |
552 | 0 | delete pSVData->maAppData.mpAccelMgr; |
553 | 0 | pSVData->maAppData.mpAccelMgr = nullptr; |
554 | 0 | } |
555 | 0 | pSVData->maAppData.maKeyListeners.clear(); |
556 | 0 | pSVData->mpBlendFrameCache.reset(); |
557 | |
|
558 | 0 | ImplDeletePrnQueueList(); |
559 | | |
560 | | // destroy all Sal interfaces before destroying the instance |
561 | | // and thereby unloading the plugin |
562 | 0 | pSVData->mpSalSystem.reset(); |
563 | 0 | assert( !pSVData->maSchedCtx.mpSalTimer ); |
564 | 0 | delete pSVData->maSchedCtx.mpSalTimer; |
565 | 0 | pSVData->maSchedCtx.mpSalTimer = nullptr; |
566 | |
|
567 | 0 | pSVData->mpDefaultWin = nullptr; |
568 | 0 | pSVData->mpIntroWindow = nullptr; |
569 | 0 | pSVData->maAppData.mpActivePopupMenu = nullptr; |
570 | 0 | pSVData->maAppData.mpWheelWindow = nullptr; |
571 | 0 | pSVData->maGDIData.mpFirstWinGraphics = nullptr; |
572 | 0 | pSVData->maGDIData.mpLastWinGraphics = nullptr; |
573 | 0 | pSVData->maGDIData.mpFirstVirGraphics = nullptr; |
574 | 0 | pSVData->maGDIData.mpLastVirGraphics = nullptr; |
575 | 0 | pSVData->maGDIData.mpFirstPrnGraphics = nullptr; |
576 | 0 | pSVData->maGDIData.mpLastPrnGraphics = nullptr; |
577 | 0 | pSVData->maGDIData.mpFirstVirDev = nullptr; |
578 | 0 | pSVData->maGDIData.mpFirstPrinter = nullptr; |
579 | 0 | pSVData->maFrameData.mpFirstFrame = nullptr; |
580 | 0 | pSVData->maFrameData.mpAppWin = nullptr; |
581 | 0 | pSVData->maFrameData.mpActiveApplicationFrame = nullptr; |
582 | 0 | pSVData->mpWinData->mpCaptureWin = nullptr; |
583 | 0 | pSVData->mpWinData->mpLastDeacWin = nullptr; |
584 | 0 | pSVData->mpWinData->mpFirstFloat = nullptr; |
585 | 0 | pSVData->mpWinData->mpExecuteDialogs.clear(); |
586 | 0 | pSVData->mpWinData->mpExtTextInputWin = nullptr; |
587 | 0 | pSVData->mpWinData->mpTrackWin = nullptr; |
588 | 0 | pSVData->mpWinData->mpAutoScrollWin = nullptr; |
589 | 0 | pSVData->mpWinData->mpLastWheelWindow = nullptr; |
590 | |
|
591 | 0 | pSVData->maGDIData.mxScreenFontList.reset(); |
592 | 0 | pSVData->maGDIData.mxScreenFontCache.reset(); |
593 | 0 | pSVData->dropCaches(); |
594 | |
|
595 | 0 | comphelper::AccessibleEventNotifier::shutdown(); |
596 | | |
597 | | // Deinit Sal |
598 | 0 | if (pSVData->mpDefInst) |
599 | 0 | { |
600 | 0 | pSVData->mpDefInst->ReleaseYieldMutex(true); |
601 | 0 | DestroySalInstance( pSVData->mpDefInst ); |
602 | 0 | pSVData->mpDefInst = nullptr; |
603 | 0 | } |
604 | | |
605 | | // This only works on Linux. On Mac and Windows I get very |
606 | | // weird segment violations. |
607 | 0 | #if defined LINUX |
608 | 0 | delete pSVData->mpSalData; |
609 | 0 | pSVData->mpSalData = nullptr; |
610 | 0 | #endif |
611 | |
|
612 | 0 | if( pOwnSvApp ) |
613 | 0 | { |
614 | 0 | delete pOwnSvApp; |
615 | 0 | pOwnSvApp = nullptr; |
616 | 0 | } |
617 | |
|
618 | 0 | EmbeddedFontsManager::clearTemporaryFontFiles(); |
619 | 0 | } |
620 | | |
621 | | namespace { |
622 | | |
623 | | // only one call is allowed |
624 | | struct WorkerThreadData |
625 | | { |
626 | | oslWorkerFunction pWorker; |
627 | | void * pThreadData; |
628 | | WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ ) |
629 | 6 | : pWorker( pWorker_ ) |
630 | 6 | , pThreadData( pThreadData_ ) |
631 | 6 | { |
632 | 6 | } |
633 | | }; |
634 | | |
635 | | } |
636 | | |
637 | | #ifdef _WIN32 |
638 | | static HANDLE hThreadID = nullptr; |
639 | | static unsigned __stdcall threadmain(void* pArgs) |
640 | | { |
641 | | OleInitialize( nullptr ); |
642 | | static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData ); |
643 | | delete static_cast<WorkerThreadData*>(pArgs); |
644 | | OleUninitialize(); |
645 | | hThreadID = nullptr; |
646 | | return 0; |
647 | | } |
648 | | #else |
649 | | static oslThread hThreadID = nullptr; |
650 | | extern "C" |
651 | | { |
652 | | static void MainWorkerFunction( void* pArgs ) |
653 | 6 | { |
654 | 6 | static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData ); |
655 | 6 | delete static_cast<WorkerThreadData*>(pArgs); |
656 | 6 | hThreadID = nullptr; |
657 | 6 | } |
658 | | } // extern "C" |
659 | | #endif |
660 | | |
661 | | void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData ) |
662 | 6 | { |
663 | | #ifdef _WIN32 |
664 | | // sal thread always call CoInitializeEx, so a system dependent implementation is necessary |
665 | | |
666 | | hThreadID = reinterpret_cast<HANDLE>(_beginthreadex( |
667 | | nullptr, // no security handle |
668 | | 0, // stacksize 0 means default |
669 | | threadmain, // thread worker function |
670 | | new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function |
671 | | 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED |
672 | | nullptr )); // thread id to fill |
673 | | #else |
674 | 6 | hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) ); |
675 | 6 | #endif |
676 | 6 | } |
677 | | |
678 | | void JoinMainLoopThread() |
679 | 0 | { |
680 | 0 | if( hThreadID ) |
681 | 0 | { |
682 | | #ifdef _WIN32 |
683 | | WaitForSingleObject(hThreadID, INFINITE); |
684 | | #else |
685 | 0 | osl_joinWithThread(hThreadID); |
686 | 0 | osl_destroyThread( hThreadID ); |
687 | 0 | #endif |
688 | 0 | } |
689 | 0 | } |
690 | | |
691 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |